song->album; refactor shelf

This commit is contained in:
Your Name 2022-12-29 23:49:28 -05:00
parent f24df6c0fd
commit bde7ce47a3
7 changed files with 261 additions and 203 deletions

View file

@ -65,7 +65,7 @@ def query_item_category(item_category):
# return q
ct = all_content_types()
contenttype_ids = [ct[cls] for cls in classes]
return Q(item__polymorphic_ctype__in=sorted(contenttype_ids))
return Q(item__polymorphic_ctype__in=contenttype_ids)
class Piece(PolymorphicModel, UserOwnedObjectMixin):
@ -325,6 +325,9 @@ class List(Piece):
def recent_members(self):
return self.members.all().order_by("-created_time")
def get_members_in_category(self, item_category):
return self.members.all().filter(query_item_category(item_category))
def get_member_for_item(self, item):
return self.members.filter(item=item).first()
@ -459,44 +462,16 @@ class ShelfMember(ListMember):
class Shelf(List):
class Meta:
unique_together = [["owner", "item_category", "shelf_type"]]
unique_together = [["owner", "shelf_type"]]
MEMBER_CLASS = ShelfMember
items = models.ManyToManyField(Item, through="ShelfMember", related_name="+")
item_category = models.CharField(
choices=ItemCategory.choices, max_length=100, null=False, blank=False
)
shelf_type = models.CharField(
choices=ShelfType.choices, max_length=100, null=False, blank=False
)
def __str__(self):
return f"{self.id} {self.title}"
@cached_property
def item_category_label(self):
return ItemCategory(self.item_category).label
@cached_property
def shelf_label(self):
return next(
iter(
[
n[2]
for n in iter(ShelfTypeNames)
if n[0] == self.item_category and n[1] == self.shelf_type
]
),
self.shelf_type,
)
@cached_property
def title(self):
q = _("{shelf_label}{item_category}").format(
shelf_label=self.shelf_label, item_category=self.item_category_label
)
return q
# return _("{user}'s {shelf_name}").format(user=self.owner.mastodon_username, shelf_name=q)
return f"{self.id} [{self.owner} {self.shelf_type} list]"
class ShelfLogEntry(models.Model):
@ -526,39 +501,31 @@ class ShelfManager:
def __init__(self, user):
self.owner = user
qs = Shelf.objects.filter(owner=self.owner)
self.shelf_list = {v.shelf_type: v for v in qs}
if len(self.shelf_list) == 0:
self.initialize()
def initialize(self):
for ic in ItemCategory:
for qt in ShelfType:
Shelf.objects.create(owner=self.owner, item_category=ic, shelf_type=qt)
self.shelf_list[qt] = Shelf.objects.create(owner=self.owner, shelf_type=qt)
def _shelf_member_for_item(self, item):
def locate_item(self, item) -> ShelfMember:
return ShelfMember.objects.filter(
item=item, parent__in=self.owner.shelf_set.all()
item=item, parent__in=list(self.shelf_list.values())
).first()
def _shelf_for_item_and_type(self, item, shelf_type):
if not item or not shelf_type:
return None
return self.owner.shelf_set.all().filter(
item_category=item.category, shelf_type=shelf_type
)
def locate_item(self, item):
member = ShelfMember.objects.filter(owner=self.owner, item=item).first()
return member # .parent if member else None
def move_item(self, item, shelf_type, visibility=0, metadata=None):
# shelf_type=None means remove from current shelf
# metadata=None means no change
if not item:
raise ValueError("empty item")
new_shelfmember = None
last_shelfmember = self._shelf_member_for_item(item)
last_shelfmember = self.locate_item(item)
last_shelf = last_shelfmember.parent if last_shelfmember else None
last_metadata = last_shelfmember.metadata if last_shelfmember else None
last_visibility = last_shelfmember.visibility if last_shelfmember else None
shelf = self.get_shelf(item.category, shelf_type) if shelf_type else None
shelf = self.shelf_list[shelf_type] if shelf_type else None
changed = False
if last_shelf != shelf: # change shelf
changed = True
@ -596,20 +563,29 @@ class ShelfManager:
"timestamp"
)
def get_shelf(self, item_category, shelf_type):
return (
self.owner.shelf_set.all()
.filter(item_category=item_category, shelf_type=shelf_type)
.first()
)
def get_shelf(self, shelf_type):
return self.shelf_list[shelf_type]
def get_items_on_shelf(self, item_category, shelf_type):
shelf = (
self.owner.shelf_set.all()
.filter(item_category=item_category, shelf_type=shelf_type)
.first()
def get_members(self, shelf_type, item_category):
return self.shelf_list[shelf_type].get_members_in_category(item_category)
# def get_items_on_shelf(self, item_category, shelf_type):
# shelf = (
# self.owner.shelf_set.all()
# .filter(item_category=item_category, shelf_type=shelf_type)
# .first()
# )
# return shelf.members.all().order_by
def get_title(self, shelf_type, item_category):
ic = ItemCategory(item_category).label
sts = [
n[2] for n in ShelfTypeNames if n[0] == item_category and n[1] == shelf_type
]
st = sts[0] if sts else shelf_type
return _("{shelf_label}{item_category}").format(
shelf_label=st, item_category=ic
)
return shelf.members.all().order_by
@staticmethod
def get_manager_for_user(user):
@ -820,7 +796,11 @@ class Mark:
@property
def shelf_label(self):
return self.shelfmember.parent.shelf_label if self.shelfmember else None
return (
self.owner.shelf_manager.get_title(self.shelf_type, self.item.category)
if self.shelfmember
else None
)
@property
def created_time(self):

View file

@ -35,12 +35,11 @@ class ShelfTest(TestCase):
def test_shelf(self):
user = User.objects.create(mastodon_site="site", username="name")
shelf_manager = ShelfManager(user=user)
shelf_manager.initialize()
self.assertEqual(user.shelf_set.all().count(), 33)
self.assertEqual(user.shelf_set.all().count(), 3)
book1 = Edition.objects.create(title="Hyperion")
book2 = Edition.objects.create(title="Andymion")
q1 = shelf_manager.get_shelf(ItemCategory.Book, ShelfType.WISHLIST)
q2 = shelf_manager.get_shelf(ItemCategory.Book, ShelfType.PROGRESS)
q1 = shelf_manager.get_shelf(ShelfType.WISHLIST)
q2 = shelf_manager.get_shelf(ShelfType.PROGRESS)
self.assertIsNotNone(q1)
self.assertIsNotNone(q2)
self.assertEqual(q1.members.all().count(), 0)
@ -123,7 +122,6 @@ class MarkTest(TestCase):
def setUp(self):
self.book1 = Edition.objects.create(title="Hyperion")
self.user1 = User.objects.create(mastodon_site="site", username="name")
self.user1.shelf_manager.initialize()
pass
def test_mark(self):
@ -139,7 +137,7 @@ class MarkTest(TestCase):
mark = Mark(self.user1, self.book1)
self.assertEqual(mark.shelf_type, ShelfType.WISHLIST)
self.assertEqual(mark.shelf_label, "想读")
self.assertEqual(mark.shelf_label, "想读的书")
self.assertEqual(mark.text, "a gentle comment")
self.assertEqual(mark.rating, 9)
self.assertEqual(mark.visibility, 1)

View file

@ -380,8 +380,7 @@ def _render_list(
):
return render_user_blocked(request)
if type == "mark":
shelf = user.shelf_manager.get_shelf(item_category, shelf_type)
queryset = ShelfMember.objects.filter(owner=user, parent=shelf)
queryset = user.shelf_manager.get_members(shelf_type, item_category)
elif type == "tagmember":
tag = Tag.objects.filter(owner=user, title=tag_title).first()
if not tag:
@ -555,10 +554,9 @@ def home(request, user_name):
for category in visbile_categories:
shelf_list[category] = {}
for shelf_type in ShelfType:
shelf = user.shelf_manager.get_shelf(category, shelf_type)
members = shelf.recent_members.filter(qv)
members = user.shelf_manager.get_members(shelf_type, category).filter(qv)
shelf_list[category][shelf_type] = {
"title": shelf.title,
"title": user.shelf_manager.get_title(shelf_type, category),
"count": members.count(),
"members": members[:5].prefetch_related("item"),
}

View file

@ -16,115 +16,133 @@ from django.db.models import Q, Count, Sum
from django.utils import dateparse, timezone
import re
from legacy.models import *
from django.db import DatabaseError, transaction
from music.models import SongMark
from collection.models import CollectionItem
BATCH_SIZE = 1000
def _book_convert(entity):
content = ResourceContent(metadata={
'title': entity.title,
'brief': entity.brief,
'cover_image_path': str(entity.cover),
'subtitle': entity.subtitle,
'orig_title': entity.orig_title,
'author': entity.author,
'translator': entity.translator,
'language': entity.language,
'pub_house': entity.pub_house,
'pub_year': entity.pub_year,
'pub_month': entity.pub_month,
'binding': entity.binding,
'price': entity.price,
'pages': entity.pages,
'contents': entity.contents,
'series': entity.other_info.get('丛书') if entity.other_info else None,
'imprint': entity.other_info.get('出品方') if entity.other_info else None,
})
content = ResourceContent(
metadata={
"title": entity.title,
"brief": entity.brief,
"cover_image_path": str(entity.cover),
"subtitle": entity.subtitle,
"orig_title": entity.orig_title,
"author": entity.author,
"translator": entity.translator,
"language": entity.language,
"pub_house": entity.pub_house,
"pub_year": entity.pub_year,
"pub_month": entity.pub_month,
"binding": entity.binding,
"price": entity.price,
"pages": entity.pages,
"contents": entity.contents,
"series": entity.other_info.get("丛书") if entity.other_info else None,
"imprint": entity.other_info.get("出品方") if entity.other_info else None,
}
)
if entity.isbn:
t, v = detect_isbn_asin(entity.isbn)
if t:
content.lookup_ids[t] = v
if entity.other_info and entity.other_info.get('统一书号'):
content.lookup_ids[IdType.CUBN] = entity.other_info.get('统一书号')
if entity.other_info and entity.other_info.get("统一书号"):
content.lookup_ids[IdType.CUBN] = entity.other_info.get("统一书号")
return content
def _album_convert(entity):
content = ResourceContent(metadata={
'title': entity.title,
'brief': entity.brief,
'cover_image_path': str(entity.cover),
'other_title': entity.other_info.get('又名') if entity.other_info else None,
'album_type': entity.other_info.get('专辑类型') if entity.other_info else None,
'media': entity.other_info.get('介质') if entity.other_info else None,
'disc_count': entity.other_info.get('碟片数') if entity.other_info else None,
'artist': entity.artist,
'genre': entity.genre,
'release_date': entity.release_date.strftime('%Y-%m-%d') if entity.release_date else None,
'duration': entity.duration,
'company': entity.company,
'track_list': entity.track_list,
'bandcamp_album_id': entity.other_info.get('bandcamp_album_id') if entity.other_info else None,
})
if entity.other_info and entity.other_info.get('ISRC'):
content.lookup_ids[IdType.ISRC] = entity.other_info.get('ISRC')
if entity.other_info and entity.other_info.get('条形码'):
content.lookup_ids[IdType.GTIN] = entity.other_info.get('条形码')
if entity.other_info and entity.other_info.get('UPC'):
content.lookup_ids[IdType.GTIN] = entity.other_info.get('UPC')
content = ResourceContent(
metadata={
"title": entity.title,
"brief": entity.brief,
"cover_image_path": str(entity.cover),
"other_title": entity.other_info.get("又名") if entity.other_info else None,
"album_type": entity.other_info.get("专辑类型") if entity.other_info else None,
"media": entity.other_info.get("介质") if entity.other_info else None,
"disc_count": entity.other_info.get("碟片数") if entity.other_info else None,
"artist": entity.artist,
"genre": entity.genre,
"release_date": entity.release_date.strftime("%Y-%m-%d")
if entity.release_date
else None,
"duration": entity.duration,
"company": entity.company,
"track_list": entity.track_list,
"bandcamp_album_id": entity.other_info.get("bandcamp_album_id")
if entity.other_info
else None,
}
)
if entity.other_info and entity.other_info.get("ISRC"):
content.lookup_ids[IdType.ISRC] = entity.other_info.get("ISRC")
if entity.other_info and entity.other_info.get("条形码"):
content.lookup_ids[IdType.GTIN] = entity.other_info.get("条形码")
if entity.other_info and entity.other_info.get("UPC"):
content.lookup_ids[IdType.GTIN] = entity.other_info.get("UPC")
return content
def _game_convert(entity):
content = ResourceContent(metadata={
'title': entity.title,
'brief': entity.brief,
'cover_image_path': str(entity.cover),
'other_title': entity.other_title,
'developer': entity.developer,
'publisher': entity.publisher,
'release_date': entity.release_date.strftime('%Y-%m-%d') if entity.release_date else None,
'genre': entity.genre,
'platform': entity.platform,
'official_site': entity.other_info.get('official_site') if entity.other_info else None,
})
if entity.other_info and entity.other_info.get('steam_url'):
content.lookup_ids[IdType.Steam] = re.search(r'store\.steampowered\.com/app/(\d+)', entity.other_info.get('steam_url'))[1]
content = ResourceContent(
metadata={
"title": entity.title,
"brief": entity.brief,
"cover_image_path": str(entity.cover),
"other_title": entity.other_title,
"developer": entity.developer,
"publisher": entity.publisher,
"release_date": entity.release_date.strftime("%Y-%m-%d")
if entity.release_date
else None,
"genre": entity.genre,
"platform": entity.platform,
"official_site": entity.other_info.get("official_site")
if entity.other_info
else None,
}
)
if entity.other_info and entity.other_info.get("steam_url"):
content.lookup_ids[IdType.Steam] = re.search(
r"store\.steampowered\.com/app/(\d+)", entity.other_info.get("steam_url")
)[1]
return content
def _movie_tv_convert(entity):
content = ResourceContent(metadata={
'title': entity.title,
'brief': entity.brief,
'cover_image_path': str(entity.cover),
'orig_title': entity.orig_title,
'other_title': entity.other_title,
'director': entity.director,
'playwright': entity.playwright,
'actor': entity.actor,
'genre': entity.genre,
'showtime': entity.showtime,
'site': entity.site,
'area': entity.area,
'language': entity.language,
'year': entity.year,
'duration': entity.duration,
'season_count': entity.other_info.get('Seasons') if entity.other_info else None,
'season_number': entity.season,
'episode_count': entity.episodes,
'single_episode_length': entity.single_episode_length,
'is_series': entity.is_series,
})
content = ResourceContent(
metadata={
"title": entity.title,
"brief": entity.brief,
"cover_image_path": str(entity.cover),
"orig_title": entity.orig_title,
"other_title": entity.other_title,
"director": entity.director,
"playwright": entity.playwright,
"actor": entity.actor,
"genre": entity.genre,
"showtime": entity.showtime,
"site": entity.site,
"area": entity.area,
"language": entity.language,
"year": entity.year,
"duration": entity.duration,
"season_count": entity.other_info.get("Seasons")
if entity.other_info
else None,
"season_number": entity.season,
"episode_count": entity.episodes,
"single_episode_length": entity.single_episode_length,
"is_series": entity.is_series,
}
)
if entity.imdb_code:
content.lookup_ids[IdType.IMDB] = entity.imdb_code
if entity.other_info and entity.other_info.get('TMDB_ID'):
content.lookup_ids[IdType.TMDB_TV] = entity.other_info.get('TMDB_ID')
if entity.other_info and entity.other_info.get("TMDB_ID"):
content.lookup_ids[IdType.TMDB_TV] = entity.other_info.get("TMDB_ID")
return content
@ -147,33 +165,77 @@ model_link = {
class Command(BaseCommand):
help = 'Migrate legacy catalog'
help = "Migrate legacy catalog"
def add_arguments(self, parser):
parser.add_argument('--book', dest='types', action='append_const', const=Legacy_Book)
parser.add_argument('--movie', dest='types', action='append_const', const=Legacy_Movie)
parser.add_argument('--album', dest='types', action='append_const', const=Legacy_Album)
parser.add_argument('--game', dest='types', action='append_const', const=Legacy_Game)
parser.add_argument('--id', help='id to convert; or, if using with --max-id, the min id')
parser.add_argument('--maxid', help='max id to convert')
parser.add_argument('--failstop', help='stop on fail', action='store_true')
parser.add_argument('--clearlink', help='clear legacy link table', action='store_true')
parser.add_argument('--reload', help='reload and ignore existing ExternalResource', action='store_true')
parser.add_argument(
"--book", dest="types", action="append_const", const=Legacy_Book
)
parser.add_argument(
"--movie", dest="types", action="append_const", const=Legacy_Movie
)
parser.add_argument(
"--album", dest="types", action="append_const", const=Legacy_Album
)
parser.add_argument(
"--game", dest="types", action="append_const", const=Legacy_Game
)
parser.add_argument("--song", help="process songs", action="store_true")
parser.add_argument(
"--id", help="id to convert; or, if using with --max-id, the min id"
)
parser.add_argument("--maxid", help="max id to convert")
parser.add_argument("--failstop", help="stop on fail", action="store_true")
parser.add_argument(
"--clearlink", help="clear legacy link table", action="store_true"
)
parser.add_argument(
"--reload",
help="reload and ignore existing ExternalResource",
action="store_true",
)
def process_song(self, entity):
if entity.album:
new_uid = AlbumLink.objects.get(old_id=entity.album.id).new_uid
else:
new_uid = Album.objects.create(
title=entity.title,
brief=entity.brief,
cover=entity.cover,
artist=entity.artist,
).uid
if SongLink.objects.filter(old_id=entity.id).count() == 0:
SongLink.objects.create(old_id=entity.id, new_uid=new_uid)
def handle(self, *args, **options):
types = options['types'] or [Legacy_Game, Legacy_Album, Legacy_Movie, Legacy_Book]
reload = options['reload']
if options["song"]:
for sm in SongMark.objects.all():
self.process_song(sm.song)
for ci in CollectionItem.objects.filter(song__isnull=False):
self.process_song(ci.song)
return
types = options["types"] or [
Legacy_Game,
Legacy_Album,
Legacy_Movie,
Legacy_Book,
]
reload = options["reload"]
for typ in types:
print(typ)
LinkModel = model_link[typ]
if options['clearlink']:
if options["clearlink"]:
LinkModel.objects.all().delete()
qs = typ.objects.all().order_by('id')
if options['id']:
if options['maxid']:
qs = qs.filter(id__gte=int(options['id']), id__lte=int(options['maxid']))
qs = typ.objects.all().order_by("id")
if options["id"]:
if options["maxid"]:
qs = qs.filter(
id__gte=int(options["id"]), id__lte=int(options["maxid"])
)
else:
qs = qs.filter(id=int(options['id']))
qs = qs.filter(id=int(options["id"]))
pg = Paginator(qs, BATCH_SIZE)
for p in tqdm(pg.page_range):
@ -185,34 +247,47 @@ class Command(BaseCommand):
site = SiteManager.get_site_by_url(entity.source_url)
item = None
if site:
if not site.DEFAULT_MODEL and not content.metadata.get('preferred_model'):
if not site.DEFAULT_MODEL and not content.metadata.get(
"preferred_model"
):
if model_map[typ] == Movie and entity.is_series:
content.metadata['preferred_model'] = 'TVSeason' if entity.season else 'TVShow'
content.metadata["preferred_model"] = (
"TVSeason" if entity.season else "TVShow"
)
else:
content.metadata['preferred_model'] = model_map[typ].__name__
item = site.get_resource_ready(preloaded_content=content, ignore_existing_content=reload).item
content.metadata["preferred_model"] = model_map[
typ
].__name__
item = site.get_resource_ready(
preloaded_content=content,
ignore_existing_content=reload,
).item
else:
# not known site, try save item without external resource
item = None
model = Edition
model = model_map[typ]
t, v = None, None
if content.lookup_ids:
t, v = Item.get_best_lookup_id(content.lookup_ids)
item = model.objects.filter(primary_lookup_id_type=t, primary_lookup_id_value=v).first()
item = model.objects.filter(
primary_lookup_id_type=t,
primary_lookup_id_value=v,
).first()
if not item:
obj = model.copy_metadata(content.metadata)
obj['primary_lookup_id_type'] = t
obj['primary_lookup_id_value'] = v
obj["primary_lookup_id_type"] = t
obj["primary_lookup_id_value"] = v
item = model.objects.create(**obj)
item.cover = content.metadata['cover_image_path']
item.cover = content.metadata["cover_image_path"]
item.last_editor = entity.last_editor
item.save()
links.append(LinkModel(old_id=entity.id, new_uid=item.uid))
# pprint.pp(site.get_item())
except Exception as e:
print(f'Convert failed for {typ} {entity.id}: {e}')
if options['failstop']:
raise(e)
print(f"Convert failed for {typ} {entity.id}: {e}")
if options["failstop"]:
raise (e)
# return
LinkModel.objects.bulk_create(links)
self.stdout.write(self.style.SUCCESS(f'Done.'))
self.stdout.write(self.style.SUCCESS(f"Done."))

View file

@ -6,7 +6,7 @@ from games.models import Game as Legacy_Game
from common.models import MarkStatusEnum
from books.models import BookMark, BookReview
from movies.models import MovieMark, MovieReview
from music.models import AlbumMark, AlbumReview
from music.models import AlbumMark, AlbumReview, SongMark, SongReview
from games.models import GameMark, GameReview
from collection.models import Collection as Legacy_Collection
from collection.models import CollectionMark as Legacy_CollectionMark
@ -35,14 +35,17 @@ model_link = {
MovieMark: MovieLink,
AlbumMark: AlbumLink,
GameMark: GameLink,
SongMark: SongLink,
BookReview: BookLink,
MovieReview: MovieLink,
AlbumReview: AlbumLink,
GameReview: GameLink,
SongReview: SongLink,
Legacy_Book: BookLink,
Legacy_Movie: MovieLink,
Legacy_Album: AlbumLink,
Legacy_Game: GameLink,
Legacy_Song: SongLink,
}
shelf_map = {
@ -55,6 +58,7 @@ tag_map = {
BookMark: "bookmark_tags",
MovieMark: "moviemark_tags",
AlbumMark: "albummark_tags",
SongMark: "songmark_tags",
GameMark: "gamemark_tags",
}
@ -75,6 +79,9 @@ class Command(BaseCommand):
parser.add_argument(
"--game", dest="types", action="append_const", const=GameMark
)
parser.add_argument(
"--song", dest="types", action="append_const", const=SongMark
)
parser.add_argument(
"--mark",
help="migrate shelves/tags/ratings, then exit",
@ -104,7 +111,7 @@ class Command(BaseCommand):
print("Initialize shelves")
with transaction.atomic():
for user in tqdm(User.objects.filter(is_active=True)):
user.shelf_manager.initialize()
temp = user.shelf_manager
def clear(self, classes):
print("Deleting migrated user pieces")
@ -196,12 +203,11 @@ class Command(BaseCommand):
raise (e)
def mark(self, options):
types = options["types"] or [GameMark, AlbumMark, MovieMark, BookMark]
types = options["types"] or [GameMark, SongMark, AlbumMark, MovieMark, BookMark]
print("Preparing cache")
tag_cache = {f"{t.owner_id}_{t.title}": t.id for t in Tag.objects.all()}
shelf_cache = {
f"{s.owner_id}_{s.item_category}_{shelf_map[s.shelf_type]}": s.id
for s in Shelf.objects.all()
f"{s.owner_id}_{shelf_map[s.shelf_type]}": s.id for s in Shelf.objects.all()
}
for typ in types:
@ -255,9 +261,7 @@ class Command(BaseCommand):
text=entity.text,
visibility=visibility,
)
shelf = shelf_cache[
f"{user_id}_{item.category}_{entity.status}"
]
shelf = shelf_cache[f"{user_id}_{entity.status}"]
ShelfMember.objects.create(
parent_id=shelf,
owner_id=user_id,
@ -309,7 +313,7 @@ class Command(BaseCommand):
elif options["mark"]:
if options["clear"]:
self.clear(
[Comment, Rating, TagMember, Tag, ShelfLogEntry, ShelfMember]
[Comment, Rating, TagMember, Tag, ShelfLogEntry, ShelfMember, Shelf]
)
else:
self.mark(options)

View file

@ -16,6 +16,11 @@ class AlbumLink(models.Model):
new_uid = models.UUIDField()
class SongLink(models.Model):
old_id = models.IntegerField(db_index=True)
new_uid = models.UUIDField()
class GameLink(models.Model):
old_id = models.IntegerField(db_index=True)
new_uid = models.UUIDField()

View file

@ -11,9 +11,7 @@ class SocialTest(TestCase):
self.book2 = Edition.objects.create(title="Andymion")
self.movie = Edition.objects.create(title="Fight Club")
self.alice = User.objects.create(mastodon_site="MySpace", username="Alice")
self.alice.shelf_manager.initialize()
self.bob = User.objects.create(mastodon_site="KKCity", username="Bob")
self.bob.shelf_manager.initialize()
def test_timeline(self):
# alice see 0 activity in timeline in the beginning
@ -40,8 +38,8 @@ class SocialTest(TestCase):
self.assertEqual(len(timeline2), 0)
# bob follows alice, see 2 activities
self.bob.mastodon_following = ['Alice@MySpace']
self.alice.mastodon_follower = ['Bob@KKCity']
self.bob.mastodon_following = ["Alice@MySpace"]
self.alice.mastodon_follower = ["Bob@KKCity"]
self.bob.following = self.bob.get_following_ids()
timeline2 = self.bob.activity_manager.get_timeline()
self.assertEqual(len(timeline2), 2)