diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index cfaf2a0c..c79c5be6 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -37,5 +37,4 @@ jobs: pip install -r requirements.txt - name: Run Tests run: | - python manage.py makemigrations contenttypes auth mastodon users common management catalog journal social legacy python manage.py test diff --git a/.gitignore b/.gitignore index 754760cb..906ad8d6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,11 +12,6 @@ __pycache__/ # flake8 tox.ini -# ignore migrations for now -migrations/ - -# docs/ - # Local sqlite3 db *.sqlite3 diff --git a/catalog/migrations/0001_initial.py b/catalog/migrations/0001_initial.py new file mode 100644 index 00000000..e509703a --- /dev/null +++ b/catalog/migrations/0001_initial.py @@ -0,0 +1,203 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +import catalog.common.mixins +import catalog.common.utils +from django.db import migrations, models +import django.db.models.deletion +import simple_history.models +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='ExternalResource', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id_type', models.CharField(choices=[('wikidata', '维基数据'), ('isbn10', 'ISBN10'), ('isbn', 'ISBN'), ('asin', 'ASIN'), ('issn', 'ISSN'), ('cubn', '统一书号'), ('isrc', 'ISRC'), ('gtin', 'GTIN UPC EAN码'), ('feed', 'Feed URL'), ('imdb', 'IMDb'), ('tmdb_tv', 'TMDB剧集'), ('tmdb_tvseason', 'TMDB剧集'), ('tmdb_tvepisode', 'TMDB剧集'), ('tmdb_movie', 'TMDB电影'), ('goodreads', 'Goodreads'), ('goodreads_work', 'Goodreads著作'), ('googlebooks', '谷歌图书'), ('doubanbook', '豆瓣读书'), ('doubanbook_work', '豆瓣读书著作'), ('doubanmovie', '豆瓣电影'), ('doubanmusic', '豆瓣音乐'), ('doubangame', '豆瓣游戏'), ('doubandrama', '豆瓣舞台剧'), ('bandcamp', 'Bandcamp'), ('spotify_album', 'Spotify专辑'), ('spotify_show', 'Spotify播客'), ('discogs_release', 'Discogs Release'), ('discogs_master', 'Discogs Master'), ('musicbrainz', 'MusicBrainz ID'), ('doubanbook_author', '豆瓣读书作者'), ('doubanmovie_celebrity', '豆瓣电影影人'), ('goodreads_author', 'Goodreads作者'), ('spotify_artist', 'Spotify艺术家'), ('tmdb_person', 'TMDB影人'), ('igdb', 'IGDB游戏'), ('steam', 'Steam游戏'), ('bangumi', 'Bangumi'), ('apple_podcast', '苹果播客')], max_length=50, verbose_name='IdType of the source site')), + ('id_value', models.CharField(max_length=1000, verbose_name='Primary Id on the source site')), + ('url', models.CharField(max_length=1000, unique=True, verbose_name='url to the resource')), + ('cover', models.ImageField(blank=True, default='item/default.svg', upload_to=catalog.common.utils.resource_cover_path)), + ('other_lookup_ids', models.JSONField(default=dict)), + ('metadata', models.JSONField(default=dict)), + ('scraped_time', models.DateTimeField(null=True)), + ('created_time', models.DateTimeField(auto_now_add=True)), + ('edited_time', models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='HistoricalItem', + fields=[ + ('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')), + ('uid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), + ('title', models.CharField(default='', max_length=1000, verbose_name='标题')), + ('brief', models.TextField(blank=True, default='', verbose_name='简介')), + ('primary_lookup_id_type', models.CharField(max_length=50, null=True, verbose_name='主要标识类型')), + ('primary_lookup_id_value', models.CharField(max_length=1000, null=True, verbose_name='主要标识数值')), + ('metadata', models.JSONField(blank=True, default=dict, null=True, verbose_name='其它信息')), + ('cover', models.TextField(blank=True, default='item/default.svg', max_length=100, verbose_name='封面')), + ('created_time', models.DateTimeField(blank=True, editable=False)), + ('edited_time', models.DateTimeField(blank=True, editable=False)), + ('is_deleted', models.BooleanField(db_index=True, default=False)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField(db_index=True)), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ], + options={ + 'verbose_name': 'historical item', + 'verbose_name_plural': 'historical items', + 'ordering': ('-history_date', '-history_id'), + 'get_latest_by': ('history_date', 'history_id'), + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + migrations.CreateModel( + name='Item', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), + ('title', models.CharField(default='', max_length=1000, verbose_name='标题')), + ('brief', models.TextField(blank=True, default='', verbose_name='简介')), + ('primary_lookup_id_type', models.CharField(max_length=50, null=True, verbose_name='主要标识类型')), + ('primary_lookup_id_value', models.CharField(max_length=1000, null=True, verbose_name='主要标识数值')), + ('metadata', models.JSONField(blank=True, default=dict, null=True, verbose_name='其它信息')), + ('cover', models.ImageField(blank=True, default='item/default.svg', upload_to=catalog.common.utils.item_cover_path, verbose_name='封面')), + ('created_time', models.DateTimeField(auto_now_add=True)), + ('edited_time', models.DateTimeField(auto_now=True)), + ('is_deleted', models.BooleanField(db_index=True, default=False)), + ], + bases=(catalog.common.mixins.SoftDeleteMixin, models.Model), + ), + migrations.CreateModel( + name='Album', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='Collection', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='Edition', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='Game', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='Movie', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='Podcast', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='TVEpisode', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ('episode_number', models.PositiveIntegerField(null=True)), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='TVSeason', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ('season_number', models.PositiveIntegerField(null=True, verbose_name='本季序号')), + ('episode_count', models.PositiveIntegerField(null=True, verbose_name='本季集数')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='TVShow', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ('season_count', models.IntegerField(blank=True, null=True, verbose_name='总季数')), + ('episode_count', models.PositiveIntegerField(blank=True, null=True, verbose_name='总集数')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='Work', + fields=[ + ('item_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='catalog.item')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='ItemLookupId', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id_type', models.CharField(blank=True, choices=[('wikidata', '维基数据'), ('isbn10', 'ISBN10'), ('isbn', 'ISBN'), ('asin', 'ASIN'), ('issn', 'ISSN'), ('cubn', '统一书号'), ('isrc', 'ISRC'), ('gtin', 'GTIN UPC EAN码'), ('feed', 'Feed URL'), ('imdb', 'IMDb'), ('tmdb_tv', 'TMDB剧集'), ('tmdb_tvseason', 'TMDB剧集'), ('tmdb_tvepisode', 'TMDB剧集'), ('tmdb_movie', 'TMDB电影'), ('goodreads', 'Goodreads'), ('goodreads_work', 'Goodreads著作'), ('googlebooks', '谷歌图书'), ('doubanbook', '豆瓣读书'), ('doubanbook_work', '豆瓣读书著作'), ('doubanmovie', '豆瓣电影'), ('doubanmusic', '豆瓣音乐'), ('doubangame', '豆瓣游戏'), ('doubandrama', '豆瓣舞台剧'), ('bandcamp', 'Bandcamp'), ('spotify_album', 'Spotify专辑'), ('spotify_show', 'Spotify播客'), ('discogs_release', 'Discogs Release'), ('discogs_master', 'Discogs Master'), ('musicbrainz', 'MusicBrainz ID'), ('doubanbook_author', '豆瓣读书作者'), ('doubanmovie_celebrity', '豆瓣电影影人'), ('goodreads_author', 'Goodreads作者'), ('spotify_artist', 'Spotify艺术家'), ('tmdb_person', 'TMDB影人'), ('igdb', 'IGDB游戏'), ('steam', 'Steam游戏'), ('bangumi', 'Bangumi'), ('apple_podcast', '苹果播客')], max_length=50, verbose_name='源网站')), + ('id_value', models.CharField(blank=True, max_length=1000, verbose_name='源网站ID')), + ('raw_url', models.CharField(blank=True, max_length=1000, unique=True, verbose_name='源网站ID')), + ('item', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='lookup_ids', to='catalog.item')), + ], + ), + ] diff --git a/catalog/migrations/0002_initial.py b/catalog/migrations/0002_initial.py new file mode 100644 index 00000000..4214a910 --- /dev/null +++ b/catalog/migrations/0002_initial.py @@ -0,0 +1,113 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('contenttypes', '0002_remove_content_type_name'), + ('catalog', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='item', + name='last_editor', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='item', + name='merged_to_item', + field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='merged_from_items', to='catalog.item'), + ), + migrations.AddField( + model_name='item', + name='polymorphic_ctype', + field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_catalog.item_set+', to='contenttypes.contenttype'), + ), + migrations.AddField( + model_name='historicalitem', + name='history_user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='historicalitem', + name='last_editor', + field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='historicalitem', + name='merged_to_item', + field=models.ForeignKey(blank=True, db_constraint=False, default=None, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='catalog.item'), + ), + migrations.AddField( + model_name='historicalitem', + name='polymorphic_ctype', + field=models.ForeignKey(blank=True, db_constraint=False, editable=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='contenttypes.contenttype'), + ), + migrations.AddField( + model_name='externalresource', + name='item', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='external_resources', to='catalog.item'), + ), + migrations.CreateModel( + name='Performance', + fields=[ + ], + options={ + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('catalog.item',), + ), + migrations.CreateModel( + name='Series', + fields=[ + ], + options={ + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('catalog.item',), + ), + migrations.AddField( + model_name='work', + name='editions', + field=models.ManyToManyField(related_name='works', to='catalog.Edition'), + ), + migrations.AddField( + model_name='tvseason', + name='show', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='seasons', to='catalog.tvshow'), + ), + migrations.AddField( + model_name='tvepisode', + name='season', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='episodes', to='catalog.tvseason'), + ), + migrations.AddField( + model_name='tvepisode', + name='show', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='episodes', to='catalog.tvshow'), + ), + migrations.AlterUniqueTogether( + name='itemlookupid', + unique_together={('id_type', 'id_value')}, + ), + migrations.AlterIndexTogether( + name='item', + index_together={('primary_lookup_id_type', 'primary_lookup_id_value')}, + ), + migrations.AlterUniqueTogether( + name='externalresource', + unique_together={('id_type', 'id_value')}, + ), + ] diff --git a/catalog/migrations/__init__.py b/catalog/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/journal/migrations/0001_initial.py b/journal/migrations/0001_initial.py new file mode 100644 index 00000000..235779b0 --- /dev/null +++ b/journal/migrations/0001_initial.py @@ -0,0 +1,220 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +import catalog.common.utils +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import journal.mixins +import markdownx.models +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('catalog', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Piece', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=(models.Model, journal.mixins.UserOwnedObjectMixin), + ), + migrations.CreateModel( + name='Collection', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('title', models.CharField(default='', max_length=1000, verbose_name='标题')), + ('brief', models.TextField(blank=True, default='', verbose_name='简介')), + ('cover', models.ImageField(blank=True, default='item/default.svg', upload_to=catalog.common.utils.item_cover_path)), + ('collaborative', models.PositiveSmallIntegerField(default=0)), + ], + options={ + 'abstract': False, + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='CollectionMember', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('position', models.PositiveIntegerField()), + ], + options={ + 'abstract': False, + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='Comment', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('text', models.TextField()), + ], + options={ + 'abstract': False, + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='Like', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='Memo', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ], + options={ + 'abstract': False, + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='Rating', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('grade', models.PositiveSmallIntegerField(default=0, null=True, validators=[django.core.validators.MaxValueValidator(10), django.core.validators.MinValueValidator(1)])), + ], + options={ + 'abstract': False, + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='Reply', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('title', models.CharField(max_length=500, null=True)), + ('body', markdownx.models.MarkdownxField()), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='Review', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('title', models.CharField(max_length=500)), + ('body', markdownx.models.MarkdownxField()), + ], + options={ + 'abstract': False, + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='Shelf', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('shelf_type', models.CharField(choices=[('wishlist', '未开始'), ('progress', '进行中'), ('complete', '完成')], max_length=100)), + ], + bases=('journal.piece',), + ), + migrations.CreateModel( + name='ShelfMember', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('position', models.PositiveIntegerField()), + ], + options={ + 'abstract': False, + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('title', models.CharField(max_length=100, validators=[django.core.validators.RegexValidator(inverse_match=True, regex='\\s+')])), + ], + bases=('journal.piece',), + ), + migrations.CreateModel( + name='TagMember', + fields=[ + ('piece_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='journal.piece')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now)), + ('edited_time', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('position', models.PositiveIntegerField()), + ], + options={ + 'abstract': False, + }, + bases=('journal.piece',), + ), + migrations.CreateModel( + name='ShelfLogEntry', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('shelf_type', models.CharField(choices=[('wishlist', '未开始'), ('progress', '进行中'), ('complete', '完成')], max_length=100, null=True)), + ('timestamp', models.DateTimeField(default=django.utils.timezone.now)), + ('metadata', models.JSONField(default=dict)), + ('created_time', models.DateTimeField(auto_now_add=True)), + ('edited_time', models.DateTimeField(auto_now=True)), + ('item', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='catalog.item')), + ], + ), + ] diff --git a/journal/migrations/0002_initial.py b/journal/migrations/0002_initial.py new file mode 100644 index 00000000..e7c167a2 --- /dev/null +++ b/journal/migrations/0002_initial.py @@ -0,0 +1,173 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('journal', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('contenttypes', '0002_remove_content_type_name'), + ('catalog', '0002_initial'), + ] + + operations = [ + migrations.AddField( + model_name='shelflogentry', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='piece', + name='polymorphic_ctype', + field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_journal.piece_set+', to='contenttypes.contenttype'), + ), + migrations.AddField( + model_name='tagmember', + name='item', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='catalog.item'), + ), + migrations.AddField( + model_name='tagmember', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='tagmember', + name='parent', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='members', to='journal.tag'), + ), + migrations.AddField( + model_name='tag', + name='items', + field=models.ManyToManyField(through='journal.TagMember', to='catalog.Item'), + ), + migrations.AddField( + model_name='tag', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='shelfmember', + name='item', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='catalog.item'), + ), + migrations.AddField( + model_name='shelfmember', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='shelfmember', + name='parent', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='members', to='journal.shelf'), + ), + migrations.AddField( + model_name='shelf', + name='items', + field=models.ManyToManyField(related_name='_journal_shelf_items_+', through='journal.ShelfMember', to='catalog.Item'), + ), + migrations.AddField( + model_name='shelf', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='review', + name='item', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='catalog.item'), + ), + migrations.AddField( + model_name='review', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='reply', + name='reply_to_content', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replies', to='journal.piece'), + ), + migrations.AddField( + model_name='rating', + name='item', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='catalog.item'), + ), + migrations.AddField( + model_name='rating', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='memo', + name='item', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='catalog.item'), + ), + migrations.AddField( + model_name='memo', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='like', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='like', + name='target', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='likes', to='journal.piece'), + ), + migrations.AddField( + model_name='comment', + name='item', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='catalog.item'), + ), + migrations.AddField( + model_name='comment', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='collectionmember', + name='item', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='catalog.item'), + ), + migrations.AddField( + model_name='collectionmember', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='collectionmember', + name='parent', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='members', to='journal.collection'), + ), + migrations.AddField( + model_name='collection', + name='catalog_item', + field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='catalog.collection'), + ), + migrations.AddField( + model_name='collection', + name='items', + field=models.ManyToManyField(related_name='collections', through='journal.CollectionMember', to='catalog.Item'), + ), + migrations.AddField( + model_name='collection', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterUniqueTogether( + name='tag', + unique_together={('owner', 'title')}, + ), + migrations.AlterUniqueTogether( + name='shelf', + unique_together={('owner', 'shelf_type')}, + ), + ] diff --git a/journal/migrations/__init__.py b/journal/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/legacy/migrations/0001_initial.py b/legacy/migrations/0001_initial.py new file mode 100644 index 00000000..07c965c7 --- /dev/null +++ b/legacy/migrations/0001_initial.py @@ -0,0 +1,74 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='AlbumLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('old_id', models.IntegerField(unique=True)), + ('new_uid', models.UUIDField()), + ], + ), + migrations.CreateModel( + name='BookLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('old_id', models.IntegerField(unique=True)), + ('new_uid', models.UUIDField()), + ], + ), + migrations.CreateModel( + name='CollectionLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('old_id', models.IntegerField(unique=True)), + ('new_uid', models.UUIDField()), + ], + ), + migrations.CreateModel( + name='GameLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('old_id', models.IntegerField(unique=True)), + ('new_uid', models.UUIDField()), + ], + ), + migrations.CreateModel( + name='MovieLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('old_id', models.IntegerField(unique=True)), + ('new_uid', models.UUIDField()), + ], + ), + migrations.CreateModel( + name='SongLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('old_id', models.IntegerField(unique=True)), + ('new_uid', models.UUIDField()), + ], + ), + migrations.CreateModel( + name='ReviewLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('module', models.CharField(max_length=20)), + ('old_id', models.IntegerField()), + ('new_uid', models.UUIDField()), + ], + options={ + 'unique_together': {('module', 'old_id')}, + }, + ), + ] diff --git a/legacy/migrations/__init__.py b/legacy/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/management/migrations/0001_initial.py b/management/migrations/0001_initial.py new file mode 100644 index 00000000..685ed0cf --- /dev/null +++ b/management/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +from django.db import migrations, models +import markdownx.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Announcement', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ('content', markdownx.models.MarkdownxField()), + ('slug', models.SlugField(allow_unicode=True, blank=True, max_length=300, null=True, unique=True)), + ('created_time', models.DateTimeField(auto_now_add=True)), + ('edited_time', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'verbose_name': 'Announcement', + 'verbose_name_plural': 'Announcements', + }, + ), + ] diff --git a/management/migrations/__init__.py b/management/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mastodon/migrations/0001_initial.py b/mastodon/migrations/0001_initial.py new file mode 100644 index 00000000..a733f134 --- /dev/null +++ b/mastodon/migrations/0001_initial.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='CrossSiteUserInfo', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uid', models.CharField(max_length=200, verbose_name='username and original site')), + ('local_id', models.PositiveIntegerField(verbose_name='local database id')), + ('target_site', models.CharField(max_length=100, verbose_name='target site domain name')), + ('site_id', models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name='MastodonApplication', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('domain_name', models.CharField(max_length=100, unique=True, verbose_name='site domain name')), + ('app_id', models.CharField(max_length=100, verbose_name='in-site app id')), + ('client_id', models.CharField(max_length=100, verbose_name='client id')), + ('client_secret', models.CharField(max_length=100, verbose_name='client secret')), + ('vapid_key', models.CharField(blank=True, max_length=200, null=True, verbose_name='vapid key')), + ('star_mode', models.PositiveIntegerField(default=0, verbose_name='0: custom emoji; 1: unicode moon; 2: text')), + ('max_status_len', models.PositiveIntegerField(default=500, verbose_name='max toot len')), + ('is_proxy', models.BooleanField(blank=True, default=False)), + ('proxy_to', models.CharField(blank=True, default='', max_length=100)), + ], + ), + migrations.AddConstraint( + model_name='crosssiteuserinfo', + constraint=models.UniqueConstraint(fields=('uid', 'target_site'), name='unique_cross_site_user_info'), + ), + ] diff --git a/mastodon/migrations/__init__.py b/mastodon/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/misc/dev-reset.sh b/misc/dev-reset.sh index 8622e406..ecfd89b0 100755 --- a/misc/dev-reset.sh +++ b/misc/dev-reset.sh @@ -18,11 +18,9 @@ psql $* postgres -c "DROP DATABASE IF EXISTS test_neodb;" || exit $? psql $* postgres -c "CREATE DATABASE neodb ENCODING 'UTF8' LC_COLLATE='en_US.UTF-8' LC_CTYPE='en_US.UTF-8' TEMPLATE template0;" || exit $? -psql $* neodb -c "CREATE EXTENSION hstore WITH SCHEMA public;" || exit $? - find -type d -name migrations | xargs rm -rf -python3 manage.py makemigrations auth mastodon users books movies games music sync management collection common sync management timeline catalog journal social || exit $? +python3 manage.py makemigrations mastodon users management common catalog journal social legacy python3 manage.py migrate || exit $? diff --git a/social/migrations/0001_initial.py b/social/migrations/0001_initial.py new file mode 100644 index 00000000..af106bbd --- /dev/null +++ b/social/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import journal.mixins + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('journal', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='LocalActivity', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('visibility', models.PositiveSmallIntegerField(default=0)), + ('template', models.CharField(choices=[('mark_item', 'Markitem'), ('review_item', 'Reviewitem'), ('create_collection', 'Createcollection'), ('like_collection', 'Likecollection')], max_length=50)), + ('created_time', models.DateTimeField(db_index=True, default=django.utils.timezone.now)), + ('action_object', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='journal.piece')), + ], + bases=(models.Model, journal.mixins.UserOwnedObjectMixin), + ), + ] diff --git a/social/migrations/0002_initial.py b/social/migrations/0002_initial.py new file mode 100644 index 00000000..85c8c50c --- /dev/null +++ b/social/migrations/0002_initial.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('social', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='localactivity', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterIndexTogether( + name='localactivity', + index_together={('owner', 'created_time')}, + ), + ] diff --git a/social/migrations/__init__.py b/social/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py new file mode 100644 index 00000000..2c2e7dd5 --- /dev/null +++ b/users/migrations/0001_initial.py @@ -0,0 +1,87 @@ +# Generated by Django 3.2.16 on 2023-01-12 01:32 + +from django.conf import settings +import django.contrib.auth.models +import django.core.serializers.json +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import users.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('username', models.CharField(help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, verbose_name='username')), + ('following', models.JSONField(default=list)), + ('mastodon_id', models.CharField(max_length=100)), + ('mastodon_site', models.CharField(max_length=100)), + ('mastodon_token', models.CharField(default='', max_length=2048)), + ('mastodon_refresh_token', models.CharField(default='', max_length=2048)), + ('mastodon_locked', models.BooleanField(default=False)), + ('mastodon_followers', models.JSONField(default=list)), + ('mastodon_following', models.JSONField(default=list)), + ('mastodon_mutes', models.JSONField(default=list)), + ('mastodon_blocks', models.JSONField(default=list)), + ('mastodon_domain_blocks', models.JSONField(default=list)), + ('mastodon_account', models.JSONField(default=dict)), + ('mastodon_last_refresh', models.DateTimeField(default=django.utils.timezone.now)), + ('read_announcement_index', models.PositiveIntegerField(default=0)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ], + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name='Preference', + fields=[ + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='users.user')), + ('profile_layout', models.JSONField(blank=True, default=list)), + ('export_status', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder, null=True)), + ('import_status', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder, null=True)), + ('default_visibility', models.PositiveSmallIntegerField(default=0)), + ('classic_homepage', models.BooleanField(default=False)), + ('mastodon_publish_public', models.BooleanField(default=False)), + ('mastodon_append_tag', models.CharField(default='', max_length=2048)), + ('show_last_edit', models.PositiveSmallIntegerField(default=0)), + ('no_anonymous_view', models.PositiveSmallIntegerField(default=0)), + ], + ), + migrations.CreateModel( + name='Report', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(blank=True, default='', upload_to=users.models.report_image_path)), + ('is_read', models.BooleanField(default=False)), + ('submitted_time', models.DateTimeField(auto_now_add=True)), + ('message', models.CharField(max_length=1000)), + ('reported_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='accused_reports', to=settings.AUTH_USER_MODEL)), + ('submit_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sumbitted_reports', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddConstraint( + model_name='user', + constraint=models.UniqueConstraint(fields=('username', 'mastodon_site'), name='unique_user_identity'), + ), + ] diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py new file mode 100644 index 00000000..e69de29b