diff --git a/.gitignore b/.gitignore index 78029c7..172a919 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ api/db.sqlite3 frontend/.vscode/ + +api/logs.sqlite3 +__pycache__ diff --git a/api/neurona/DatabaseRouter.py b/api/neurona/DatabaseRouter.py new file mode 100644 index 0000000..a37e94e --- /dev/null +++ b/api/neurona/DatabaseRouter.py @@ -0,0 +1,20 @@ + +class DatabaseRouter: + + def db_for_read(self, model, **hints): + if model._meta.app_label == 'neuronaLogs': + return 'logs' + return 'default' + + def db_for_write(self, model, **hints): + if model._meta.app_label == 'neuronaLogs': + return 'logs' + return 'default' + + def allow_relation(self, obj1, obj2, **hints): + return True + + def allow_migrate(self, db, app_label, model_name=None, **hints): + if app_label == 'neuronaLogs': + return db == 'logs' + return None diff --git a/api/neurona/settings.py b/api/neurona/settings.py index 001ff77..2701b02 100644 --- a/api/neurona/settings.py +++ b/api/neurona/settings.py @@ -15,7 +15,6 @@ # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ @@ -27,7 +26,6 @@ ALLOWED_HOSTS = [] - # Application definition INSTALLED_APPS = [ @@ -38,6 +36,8 @@ "django.contrib.messages", "django.contrib.staticfiles", "rest_framework", + "neuronaApp", + "neuronaLogs" ] MIDDLEWARE = [ @@ -70,7 +70,6 @@ WSGI_APPLICATION = "neurona.wsgi.application" - # Database # https://docs.djangoproject.com/en/5.0/ref/settings/#databases @@ -78,9 +77,14 @@ "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3", - } + }, + "logs": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "logs.sqlite3", + }, } +DATABASE_ROUTERS = ["neurona.DatabaseRouter.DatabaseRouter"] # Password validation # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators @@ -100,7 +104,6 @@ }, ] - # Internationalization # https://docs.djangoproject.com/en/5.0/topics/i18n/ @@ -112,7 +115,6 @@ USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ diff --git a/api/neuronaApp/migrations/0001_initial.py b/api/neuronaApp/migrations/0001_initial.py new file mode 100644 index 0000000..1076d91 --- /dev/null +++ b/api/neuronaApp/migrations/0001_initial.py @@ -0,0 +1,49 @@ +# Generated by Django 5.0.2 on 2024-02-24 19:39 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Challenges', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('challenge', models.CharField(max_length=100)), + ('expires_at', models.DateTimeField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('username', models.CharField(max_length=100, unique=True)), + ('email', models.EmailField(max_length=100, unique=True)), + ('display_name', models.CharField(max_length=100)), + ('passkey_user_id', models.CharField(max_length=100)), + ('about', models.TextField(blank=True, max_length=2000)), + ('image_url', models.URLField(null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='RecoveryCodes', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=100)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='neuronaApp.user')), + ], + ), + ] diff --git a/api/neuronaApp/migrations/0002_spaces_alter_recoverycodes_user_apikeys_comments_and_more.py b/api/neuronaApp/migrations/0002_spaces_alter_recoverycodes_user_apikeys_comments_and_more.py new file mode 100644 index 0000000..5b05099 --- /dev/null +++ b/api/neuronaApp/migrations/0002_spaces_alter_recoverycodes_user_apikeys_comments_and_more.py @@ -0,0 +1,168 @@ +# Generated by Django 5.0.2 on 2024-02-24 20:28 + +import django.db.models.deletion +import neuronaApp.models.spaces_models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('neuronaApp', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Spaces', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('about', models.TextField(blank=True, max_length=2000)), + ('image_url', models.URLField(null=True)), + ('privacy', models.IntegerField(choices=[(neuronaApp.models.spaces_models.Privacy['PUBLIC'], 0), (neuronaApp.models.spaces_models.Privacy['PROTECTED'], 1), (neuronaApp.models.spaces_models.Privacy['RESTRICTED'], 2), (neuronaApp.models.spaces_models.Privacy['PRIVATE'], 3)])), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + ), + migrations.AlterField( + model_name='recoverycodes', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='recovery_codes', to='neuronaApp.user'), + ), + migrations.CreateModel( + name='ApiKeys', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(max_length=256)), + ('expires_at', models.DateTimeField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='api_keys', to='neuronaApp.user')), + ], + ), + migrations.CreateModel( + name='Comments', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content', models.TextField(max_length=1000)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='neuronaApp.user')), + ], + ), + migrations.CreateModel( + name='CommentsImages', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image_url', models.URLField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='neuronaApp.comments')), + ], + ), + migrations.CreateModel( + name='Posts', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=100)), + ('content', models.TextField(max_length=1000)), + ('is_archived', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts', to='neuronaApp.user')), + ('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts', to='neuronaApp.spaces')), + ], + ), + migrations.AddField( + model_name='comments', + name='post', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='neuronaApp.posts'), + ), + migrations.CreateModel( + name='PostsImages', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image_url', models.URLField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='neuronaApp.posts')), + ], + ), + migrations.CreateModel( + name='PublicKeys', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(max_length=5000)), + ('credential_id', models.CharField(max_length=100)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='public_keys', to='neuronaApp.user')), + ], + ), + migrations.CreateModel( + name='SpacesAccessRequests', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='access_requests', to='neuronaApp.spaces')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='access_requests', to='neuronaApp.user')), + ], + ), + migrations.CreateModel( + name='SpacesAdmins', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='admins', to='neuronaApp.spaces')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='admin_of', to='neuronaApp.user')), + ], + ), + migrations.CreateModel( + name='SpacesInvitations', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='invitations', to='neuronaApp.spaces')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='invitations', to='neuronaApp.user')), + ], + ), + migrations.CreateModel( + name='SpacesMembers', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='members', to='neuronaApp.spaces')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='spaces', to='neuronaApp.user')), + ], + ), + migrations.CreateModel( + name='Tags', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='neuronaApp.spaces')), + ], + ), + migrations.AddField( + model_name='posts', + name='tag', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts', to='neuronaApp.tags'), + ), + migrations.CreateModel( + name='Votes', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_upvote', models.BooleanField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='votes', to='neuronaApp.posts')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='votes', to='neuronaApp.user')), + ], + ), + ] diff --git a/api/neuronaApp/migrations/0003_alter_spaces_privacy.py b/api/neuronaApp/migrations/0003_alter_spaces_privacy.py new file mode 100644 index 0000000..19cbb07 --- /dev/null +++ b/api/neuronaApp/migrations/0003_alter_spaces_privacy.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.2 on 2024-02-27 21:28 + +import neuronaApp.models.spaces_models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('neuronaApp', '0002_spaces_alter_recoverycodes_user_apikeys_comments_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='spaces', + name='privacy', + field=models.CharField(choices=[(neuronaApp.models.spaces_models.Privacy['PUBLIC'], 'public'), (neuronaApp.models.spaces_models.Privacy['PROTECTED'], 'protected'), (neuronaApp.models.spaces_models.Privacy['RESTRICTED'], 'restricted'), (neuronaApp.models.spaces_models.Privacy['PRIVATE'], 'private')], max_length=100), + ), + ] diff --git a/api/neuronaApp/migrations/0004_commentsvotes.py b/api/neuronaApp/migrations/0004_commentsvotes.py new file mode 100644 index 0000000..211ca8c --- /dev/null +++ b/api/neuronaApp/migrations/0004_commentsvotes.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0.2 on 2024-02-28 08:40 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('neuronaApp', '0003_alter_spaces_privacy'), + ] + + operations = [ + migrations.CreateModel( + name='CommentsVotes', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_upvote', models.BooleanField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='votes', to='neuronaApp.comments')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments_votes', to='neuronaApp.user')), + ], + ), + ] diff --git a/api/neuronaApp/models.py b/api/neuronaApp/models.py deleted file mode 100644 index 71a8362..0000000 --- a/api/neuronaApp/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/api/neuronaApp/models/__init__.py b/api/neuronaApp/models/__init__.py new file mode 100644 index 0000000..0264ddb --- /dev/null +++ b/api/neuronaApp/models/__init__.py @@ -0,0 +1,5 @@ +from .user_models import User, Challenges, RecoveryCodes, PublicKeys, ApiKeys +from .posts_models import Posts, PostsImages, Comments, CommentsImages, Votes +from .spaces_models import Spaces, Tags, SpacesMembers, SpacesAdmins, SpacesAccessRequests, SpacesInvitations + +from neuronaLogs.models.logs_managing import * diff --git a/api/neuronaApp/models/posts_models.py b/api/neuronaApp/models/posts_models.py new file mode 100644 index 0000000..4e3c1ff --- /dev/null +++ b/api/neuronaApp/models/posts_models.py @@ -0,0 +1,49 @@ +from django.db import models + +class Posts(models.Model): + user = models.ForeignKey('User', related_name='posts', on_delete=models.CASCADE) + title = models.CharField(max_length=100) + content = models.TextField(max_length=1000) + space = models.ForeignKey('Spaces', related_name='posts', on_delete=models.CASCADE) + tag = models.ForeignKey('Tags', related_name='posts', on_delete=models.CASCADE) + is_archived = models.BooleanField(default=False) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class PostsImages(models.Model): + post = models.ForeignKey(Posts, related_name='images', on_delete=models.CASCADE) + image_url = models.URLField(max_length=200) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class Comments(models.Model): + user = models.ForeignKey('User', related_name='comments', on_delete=models.CASCADE) + post = models.ForeignKey(Posts, related_name='comments', on_delete=models.CASCADE) + content = models.TextField(max_length=1000) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class CommentsImages(models.Model): + comment = models.ForeignKey(Comments, related_name='images', on_delete=models.CASCADE) + image_url = models.URLField(max_length=200) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class Votes(models.Model): + user = models.ForeignKey('User', related_name='votes', on_delete=models.CASCADE) + post = models.ForeignKey(Posts, related_name='votes', on_delete=models.CASCADE) + is_upvote = models.BooleanField() + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class CommentsVotes(models.Model): + user = models.ForeignKey('User', related_name='comments_votes', on_delete=models.CASCADE) + comment = models.ForeignKey(Comments, related_name='votes', on_delete=models.CASCADE) + is_upvote = models.BooleanField() + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) \ No newline at end of file diff --git a/api/neuronaApp/models/spaces_models.py b/api/neuronaApp/models/spaces_models.py new file mode 100644 index 0000000..553a9e5 --- /dev/null +++ b/api/neuronaApp/models/spaces_models.py @@ -0,0 +1,52 @@ +from django.db import models +from enum import Enum + + +class Privacy(Enum): + PUBLIC = "public" + PROTECTED = "protected" + RESTRICTED = "restricted" + PRIVATE = "private" + + +class Spaces(models.Model): + name = models.CharField(max_length=100) + about = models.TextField(max_length=2000, blank=True) + image_url = models.URLField(max_length=200, null=True) + privacy = models.CharField(choices=[(tag, tag.value) for tag in Privacy], max_length=100) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class SpacesMembers(models.Model): + user = models.ForeignKey('User', related_name='spaces', on_delete=models.CASCADE) + space = models.ForeignKey(Spaces, related_name='members', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class SpacesAdmins(models.Model): + user = models.ForeignKey('User', related_name='admin_of', on_delete=models.CASCADE) + space = models.ForeignKey(Spaces, related_name='admins', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class SpacesAccessRequests(models.Model): + user = models.ForeignKey('User', related_name='access_requests', on_delete=models.CASCADE) + space = models.ForeignKey(Spaces, related_name='access_requests', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class SpacesInvitations(models.Model): + user = models.ForeignKey('User', related_name='invitations', on_delete=models.CASCADE) + space = models.ForeignKey(Spaces, related_name='invitations', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + +class Tags(models.Model): + name = models.CharField(max_length=100) + space = models.ForeignKey(Spaces, related_name='tags', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) \ No newline at end of file diff --git a/api/neuronaApp/models/user_models.py b/api/neuronaApp/models/user_models.py new file mode 100644 index 0000000..a844d96 --- /dev/null +++ b/api/neuronaApp/models/user_models.py @@ -0,0 +1,42 @@ +from django.db import models + + +class Challenges(models.Model): + challenge = models.CharField(max_length=100) + expires_at = models.DateTimeField() + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class User(models.Model): + username = models.CharField(max_length=100, unique=True) + email = models.EmailField(max_length=100, unique=True) + display_name = models.CharField(max_length=100) + passkey_user_id = models.CharField(max_length=100) + about = models.TextField(max_length=2000, blank=True) + image_url = models.URLField(max_length=200, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class RecoveryCodes(models.Model): + user = models.ForeignKey(User, related_name='recovery_codes', on_delete=models.CASCADE) + code = models.CharField(max_length=100) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class PublicKeys(models.Model): + user = models.ForeignKey(User, related_name='public_keys', on_delete=models.CASCADE) + key = models.CharField(max_length=5000) + credential_id = models.CharField(max_length=100) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + +class ApiKeys(models.Model): + user = models.ForeignKey(User, related_name='api_keys', on_delete=models.CASCADE) + key = models.CharField(max_length=256) + expires_at = models.DateTimeField() + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) \ No newline at end of file diff --git a/api/neuronaLogs/__init__.py b/api/neuronaLogs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/neuronaLogs/admin.py b/api/neuronaLogs/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/api/neuronaLogs/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/api/neuronaLogs/apps.py b/api/neuronaLogs/apps.py new file mode 100644 index 0000000..b5cb46c --- /dev/null +++ b/api/neuronaLogs/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class NeuronalogsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "neuronaLogs" diff --git a/api/neuronaLogs/migrations/0001_initial.py b/api/neuronaLogs/migrations/0001_initial.py new file mode 100644 index 0000000..5b922a3 --- /dev/null +++ b/api/neuronaLogs/migrations/0001_initial.py @@ -0,0 +1,591 @@ +# Generated by Django 5.0.2 on 2024-03-06 18:23 + +import neuronaLogs.models.logs_models +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="CommentImagesLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("comment_id", models.IntegerField()), + ("image_url", models.URLField()), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="CommentLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("comment_id", models.IntegerField()), + ("user_id", models.IntegerField()), + ("post_id", models.IntegerField()), + ("content", models.TextField(max_length=1000)), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.CommentAction["CREATED"], + "created", + ), + ( + neuronaLogs.models.logs_models.CommentAction["DELETED"], + "deleted", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="CommentVoteLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("user_id", models.IntegerField()), + ("comment_id", models.IntegerField()), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.VoteAction["UPVOTED"], + "upvoted", + ), + ( + neuronaLogs.models.logs_models.VoteAction["DOWNVOTED"], + "downvoted", + ), + ( + neuronaLogs.models.logs_models.VoteAction[ + "CANCELLED_UPVOTE" + ], + "cancelled_upvote", + ), + ( + neuronaLogs.models.logs_models.VoteAction[ + "CANCELLED_DOWNVOTE" + ], + "cancelled_downvote", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="LoginLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("user_id", models.IntegerField()), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.LoginAction["LOGGED_IN"], + "logged_in", + ), + ( + neuronaLogs.models.logs_models.LoginAction[ + "LOGGED_IN_WITH_RECOVERY_CODE" + ], + "logged_in_with_recovery_code", + ), + ( + neuronaLogs.models.logs_models.LoginAction[ + "LOGGED_OUT" + ], + "logged_out", + ), + ( + neuronaLogs.models.logs_models.LoginAction[ + "FAILED_LOGIN" + ], + "failed_login", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="PostImagesLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("post_id", models.IntegerField()), + ("image_url", models.URLField()), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="PostLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("post_id", models.IntegerField()), + ("user_id", models.IntegerField()), + ("admin_id", models.IntegerField()), + ("content", models.TextField(max_length=1000)), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.PostAction["CREATED"], + "created", + ), + ( + neuronaLogs.models.logs_models.PostAction["DELETED"], + "deleted", + ), + ( + neuronaLogs.models.logs_models.PostAction["ARCHIVED"], + "archived", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="PostVoteLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("user_id", models.IntegerField()), + ("post_id", models.IntegerField()), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.VoteAction["UPVOTED"], + "upvoted", + ), + ( + neuronaLogs.models.logs_models.VoteAction["DOWNVOTED"], + "downvoted", + ), + ( + neuronaLogs.models.logs_models.VoteAction[ + "CANCELLED_UPVOTE" + ], + "cancelled_upvote", + ), + ( + neuronaLogs.models.logs_models.VoteAction[ + "CANCELLED_DOWNVOTE" + ], + "cancelled_downvote", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="SpaceAccessRequestLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("user_id", models.IntegerField()), + ("space_id", models.IntegerField()), + ("admin_id", models.IntegerField()), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.SpaceAccessRequestAction[ + "ACCEPTED" + ], + "accepted", + ), + ( + neuronaLogs.models.logs_models.SpaceAccessRequestAction[ + "REJECTED" + ], + "rejected", + ), + ( + neuronaLogs.models.logs_models.SpaceAccessRequestAction[ + "CANCELLED" + ], + "cancelled", + ), + ( + neuronaLogs.models.logs_models.SpaceAccessRequestAction[ + "SENT" + ], + "sent", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="SpaceAdminLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("user_id", models.IntegerField()), + ("space_id", models.IntegerField()), + ("admin_id", models.IntegerField()), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.SpaceAdminAction[ + "ADDED" + ], + "added", + ), + ( + neuronaLogs.models.logs_models.SpaceAdminAction[ + "REMOVED" + ], + "removed", + ), + ( + neuronaLogs.models.logs_models.SpaceAdminAction["LEFT"], + "left", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="SpaceLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("space_id", models.IntegerField()), + ("name", models.CharField(max_length=100)), + ("about", models.TextField(blank=True, max_length=2000)), + ("image_url", models.URLField(null=True)), + ( + "privacy", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.Privacy["PUBLIC"], + "public", + ), + ( + neuronaLogs.models.logs_models.Privacy["PROTECTED"], + "protected", + ), + ( + neuronaLogs.models.logs_models.Privacy["RESTRICTED"], + "restricted", + ), + ( + neuronaLogs.models.logs_models.Privacy["PRIVATE"], + "private", + ), + ], + max_length=100, + ), + ), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.SpaceAction["CREATED"], + "created", + ), + ( + neuronaLogs.models.logs_models.SpaceAction["DELETED"], + "deleted", + ), + ( + neuronaLogs.models.logs_models.SpaceAction[ + "CHANGED_NAME" + ], + "changed_name", + ), + ( + neuronaLogs.models.logs_models.SpaceAction[ + "CHANGED_ABOUT" + ], + "changed_about", + ), + ( + neuronaLogs.models.logs_models.SpaceAction[ + "CHANGED_IMAGE" + ], + "changed_image", + ), + ( + neuronaLogs.models.logs_models.SpaceAction[ + "CHANGED_PRIVACY" + ], + "changed_privacy", + ), + ], + max_length=100, + ), + ), + ("admin_id", models.IntegerField()), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="SpaceMemberLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("user_id", models.IntegerField()), + ("space_id", models.IntegerField()), + ("admin_id", models.IntegerField()), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.SpaceMemberAction[ + "JOINED" + ], + "joined", + ), + ( + neuronaLogs.models.logs_models.SpaceMemberAction[ + "LEFT" + ], + "left", + ), + ( + neuronaLogs.models.logs_models.SpaceMemberAction[ + "KICKED" + ], + "kicked", + ), + ( + neuronaLogs.models.logs_models.SpaceMemberAction[ + "INVITED" + ], + "invited", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="TagLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("tag_id", models.IntegerField()), + ("space_id", models.IntegerField()), + ("admin_id", models.IntegerField()), + ("name", models.CharField(max_length=100)), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.TagAction["CREATED"], + "created", + ), + ( + neuronaLogs.models.logs_models.TagAction["DELETED"], + "deleted", + ), + ( + neuronaLogs.models.logs_models.TagAction[ + "CHANGED_NAME" + ], + "changed_name", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="UserLogs", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("user_id", models.IntegerField()), + ("email", models.EmailField(max_length=100)), + ("display_name", models.CharField(max_length=100)), + ("username", models.CharField(max_length=100)), + ("about", models.TextField(blank=True, max_length=2000)), + ("image_url", models.URLField(null=True)), + ( + "action", + models.CharField( + choices=[ + ( + neuronaLogs.models.logs_models.UserAction["CREATED"], + "created", + ), + ( + neuronaLogs.models.logs_models.UserAction["DELETED"], + "deleted", + ), + ( + neuronaLogs.models.logs_models.UserAction[ + "CHANGED_EMAIL" + ], + "changed_email", + ), + ( + neuronaLogs.models.logs_models.UserAction[ + "CHANGED_DISPLAY_NAME" + ], + "changed_display_name", + ), + ( + neuronaLogs.models.logs_models.UserAction[ + "CHANGED_USERNAME" + ], + "changed_username", + ), + ( + neuronaLogs.models.logs_models.UserAction[ + "CHANGED_ABOUT" + ], + "changed_about", + ), + ( + neuronaLogs.models.logs_models.UserAction[ + "CHANGED_IMAGE" + ], + "changed_image", + ), + ], + max_length=100, + ), + ), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ], + ), + ] diff --git a/api/neuronaLogs/migrations/0002_alter_commentlogs_comment_id_alter_postlogs_admin_id_and_more.py b/api/neuronaLogs/migrations/0002_alter_commentlogs_comment_id_alter_postlogs_admin_id_and_more.py new file mode 100644 index 0000000..143a3cc --- /dev/null +++ b/api/neuronaLogs/migrations/0002_alter_commentlogs_comment_id_alter_postlogs_admin_id_and_more.py @@ -0,0 +1,42 @@ +# Generated by Django 5.0.2 on 2024-03-06 18:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("neuronaLogs", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="commentlogs", + name="comment_id", + field=models.IntegerField(null=True), + ), + migrations.AlterField( + model_name="postlogs", + name="admin_id", + field=models.IntegerField(null=True), + ), + migrations.AlterField( + model_name="postlogs", + name="post_id", + field=models.IntegerField(null=True), + ), + migrations.AlterField( + model_name="spacelogs", + name="space_id", + field=models.IntegerField(null=True), + ), + migrations.AlterField( + model_name="taglogs", + name="tag_id", + field=models.IntegerField(null=True), + ), + migrations.AlterField( + model_name="userlogs", + name="user_id", + field=models.IntegerField(null=True), + ), + ] diff --git a/api/neuronaLogs/migrations/__init__.py b/api/neuronaLogs/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/neuronaLogs/models/__init__.py b/api/neuronaLogs/models/__init__.py new file mode 100644 index 0000000..eea5595 --- /dev/null +++ b/api/neuronaLogs/models/__init__.py @@ -0,0 +1,2 @@ +from .logs_managing import * +from .logs_models import * diff --git a/api/neuronaLogs/models/logs_managing.py b/api/neuronaLogs/models/logs_managing.py new file mode 100644 index 0000000..08994c1 --- /dev/null +++ b/api/neuronaLogs/models/logs_managing.py @@ -0,0 +1,159 @@ +from django.db.models.signals import pre_save, pre_delete +from django.dispatch import receiver + +from neuronaApp.models.user_models import * +from neuronaApp.models.posts_models import * +from neuronaApp.models.spaces_models import * +from .logs_models import * + + +def save_user_log(instance, action): + UserLogs( + user_id=instance.pk, + email=instance.email, + display_name=instance.display_name, + username=instance.username, + about=instance.about, + image_url=instance.image_url, + action=action + ).save() + + +@receiver(pre_save, sender=User) +def user_changes(sender, instance, **kwargs): + """ + This method is invoked before saving a User instance. + It checks which fields have been modified and logs the changes. + """ + if instance.pk: + original = sender.objects.get(pk=instance.pk) + + if original.email != instance.email: + save_user_log(instance, UserAction.CHANGED_EMAIL) + + if original.display_name != instance.display_name: + save_user_log(instance, UserAction.CHANGED_DISPLAY_NAME) + + if original.username != instance.username: + save_user_log(instance, UserAction.CHANGED_USERNAME) + + if original.about != instance.about: + save_user_log(instance, UserAction.CHANGED_ABOUT) + + if original.image_url != instance.image_url: + save_user_log(instance, UserAction.CHANGED_IMAGE) + + else: + save_user_log(instance, UserAction.CREATED) + + +def save_post_log(instance: Posts, action, admin_id=None): + PostLogs( + post_id=instance.pk, + user_id=instance.user_id, + admin_id=admin_id, + content=instance.content, + action=action + ).save() + + +@receiver(pre_save, sender=Posts) +def post_created_or_archived(sender, instance: Posts, **kwargs): + """ + """ + if instance.pk: + original = sender.objects.get(pk=instance.pk) + + if original.is_archived != instance.is_archived: + save_post_log(instance, PostAction.ARCHIVED) + + else: + save_post_log(instance, PostAction.CREATED) + + +@receiver(pre_delete, sender=Posts) +def post_deleted(sender, instance, **kwargs): + save_post_log(instance, PostAction.DELETED) + + +@receiver(pre_save, sender=PostsImages) +def post_image_added(sender, instance, **kwargs): + """ + """ + PostImagesLogs( + post_id=instance.post_id, + image_url=instance.image_url + ).save() + + +def save_post_vote_log(instance: Votes, action): + PostVoteLogs( + post_id=instance.post_id, + user_id=instance.user_id, + action=action + ).save() + + +@receiver(pre_save, sender=Votes) +def post_vote_changes(sender, instance: Votes, **kwargs): + action = VoteAction.UPVOTED if instance.is_upvote else VoteAction.DOWNVOTED + save_post_vote_log(instance, action) + + +@receiver(pre_delete, sender=Votes) +def post_vote_deleted(sender, instance: Votes, **kwargs): + action = VoteAction.CANCELLED_UPVOTE if instance.is_upvote else VoteAction.CANCELLED_DOWNVOTE + save_post_vote_log(instance, action) + + +def save_comment_log(instance: Comments, action: CommentAction): + CommentLogs( + comment_id=instance.pk, + user_id=instance.user_id, + post_id=instance.post_id, + content=instance.content, + action=action + ).save() + + +@receiver(pre_save, sender=Comments) +def comment_created(sender, instance: Comments, **kwargs): + save_comment_log(instance, CommentAction.CREATED) + + +@receiver(pre_delete, sender=Comments) +def comment_deleted(sender, instance: Comments, **kwargs): + save_comment_log(instance, CommentAction.DELETED) + + +def save_comment_vote_logs(instance: CommentsVotes, action: VoteAction): + CommentVoteLogs( + comment_id=instance.comment_id, + user_id=instance.user_id, + action=action + ).save() + + +@receiver(pre_save, sender=CommentsVotes) +def comment_vote_changes(sender, instance: CommentsVotes, **kwargs): + action = VoteAction.UPVOTED if instance.is_upvote else VoteAction.DOWNVOTED + save_comment_vote_logs(instance, action) + + +@receiver(pre_delete, sender=CommentsVotes) +def comment_vote_deleted(sender, instance: CommentsVotes, **kwargs): + action = VoteAction.CANCELLED_UPVOTE if instance.is_upvote else VoteAction.CANCELLED_DOWNVOTE + save_comment_vote_logs(instance, action) + + +def save_comment_image_log(instance: CommentsImages): + CommentImagesLogs( + comment_id=instance.comment_id, + image_url=instance.image_url + ).save() + + +@receiver(pre_save, sender=CommentsImages) +def comment_images_created(sender, instance: CommentsImages, **kwargs): + save_comment_image_log(instance) + diff --git a/api/neuronaLogs/models/logs_models.py b/api/neuronaLogs/models/logs_models.py new file mode 100644 index 0000000..0501485 --- /dev/null +++ b/api/neuronaLogs/models/logs_models.py @@ -0,0 +1,223 @@ +from django.db import models +from enum import Enum + + +class Privacy(Enum): + PUBLIC = "public" + PROTECTED = "protected" + RESTRICTED = "restricted" + PRIVATE = "private" + + +class UserAction(Enum): + CREATED = "created" + DELETED = "deleted" + CHANGED_EMAIL = "changed_email" + CHANGED_DISPLAY_NAME = "changed_display_name" + CHANGED_USERNAME = "changed_username" + CHANGED_ABOUT = "changed_about" + CHANGED_IMAGE = "changed_image" + + +class UserLogs(models.Model): + user_id = models.IntegerField(null=True) + email = models.EmailField(max_length=100) + display_name = models.CharField(max_length=100) + username = models.CharField(max_length=100) + about = models.TextField(max_length=2000, blank=True) + image_url = models.URLField(max_length=200, null=True) + action = models.CharField(choices=[(tag, tag.value) for tag in UserAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class PostAction(Enum): + CREATED = "created" + DELETED = "deleted" + ARCHIVED = "archived" + + +class PostLogs(models.Model): + post_id = models.IntegerField(null=True) + user_id = models.IntegerField() + admin_id = models.IntegerField(null=True) + content = models.TextField(max_length=1000) + action = models.CharField(choices=[(tag, tag.value) for tag in PostAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class PostImagesLogs(models.Model): + post_id = models.IntegerField() + image_url = models.URLField(max_length=200) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class VoteAction(Enum): + UPVOTED = "upvoted" + DOWNVOTED = "downvoted" + CANCELLED_UPVOTE = "cancelled_upvote" + CANCELLED_DOWNVOTE = "cancelled_downvote" + + +class PostVoteLogs(models.Model): + user_id = models.IntegerField() + post_id = models.IntegerField() + action = models.CharField(choices=[(tag, tag.value) for tag in VoteAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class CommentAction(Enum): + CREATED = "created" + DELETED = "deleted" + + +class CommentLogs(models.Model): + comment_id = models.IntegerField(null=True) + user_id = models.IntegerField() + post_id = models.IntegerField() + content = models.TextField(max_length=1000) + action = models.CharField(choices=[(tag, tag.value) for tag in CommentAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class CommentImagesLogs(models.Model): + comment_id = models.IntegerField() + image_url = models.URLField(max_length=200) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class CommentVoteLogs(models.Model): + user_id = models.IntegerField() + comment_id = models.IntegerField() + action = models.CharField(choices=[(tag, tag.value) for tag in VoteAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class SpaceAction(Enum): + CREATED = "created" + DELETED = "deleted" + CHANGED_NAME = "changed_name" + CHANGED_ABOUT = "changed_about" + CHANGED_IMAGE = "changed_image" + CHANGED_PRIVACY = "changed_privacy" + + +class SpaceLogs(models.Model): + space_id = models.IntegerField(null=True) + name = models.CharField(max_length=100) + about = models.TextField(max_length=2000, blank=True) + image_url = models.URLField(max_length=200, null=True) + privacy = models.CharField(choices=[(tag, tag.value) for tag in Privacy], max_length=100) + action = models.CharField(choices=[(tag, tag.value) for tag in SpaceAction], max_length=100) + admin_id = models.IntegerField() + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class SpaceMemberAction(Enum): + JOINED = "joined" + LEFT = "left" + KICKED = "kicked" + INVITED = "invited" + + +class SpaceMemberLogs(models.Model): + user_id = models.IntegerField() + space_id = models.IntegerField() + admin_id = models.IntegerField() + action = models.CharField(choices=[(tag, tag.value) for tag in SpaceMemberAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class SpaceAdminAction(Enum): + ADDED = "added" + REMOVED = "removed" + LEFT = "left" + + +class SpaceAdminLogs(models.Model): + user_id = models.IntegerField() + space_id = models.IntegerField() + admin_id = models.IntegerField() + action = models.CharField(choices=[(tag, tag.value) for tag in SpaceAdminAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class SpaceAccessRequestAction(Enum): + ACCEPTED = "accepted" + REJECTED = "rejected" + CANCELLED = "cancelled" + SENT = "sent" + + +class SpaceAccessRequestLogs(models.Model): + user_id = models.IntegerField() + space_id = models.IntegerField() + admin_id = models.IntegerField() + action = models.CharField(choices=[(tag, tag.value) for tag in SpaceAccessRequestAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class TagAction(Enum): + CREATED = "created" + DELETED = "deleted" + CHANGED_NAME = "changed_name" + + +class TagLogs(models.Model): + tag_id = models.IntegerField(null=True) + space_id = models.IntegerField() + admin_id = models.IntegerField() + name = models.CharField(max_length=100) + action = models.CharField(choices=[(tag, tag.value) for tag in TagAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' + + +class LoginAction(Enum): + LOGGED_IN = "logged_in" + LOGGED_IN_WITH_RECOVERY_CODE = "logged_in_with_recovery_code" + LOGGED_OUT = "logged_out" + FAILED_LOGIN = "failed_login" + + +class LoginLogs(models.Model): + user_id = models.IntegerField() + action = models.CharField(choices=[(tag, tag.value) for tag in LoginAction], max_length=100) + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'neuronaLogs' diff --git a/api/neuronaLogs/tests.py b/api/neuronaLogs/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/api/neuronaLogs/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/api/neuronaLogs/views.py b/api/neuronaLogs/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/api/neuronaLogs/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here.