diff --git a/api/__pycache__/__init__.cpython-313.pyc b/api/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94c5cc886d53ee1297f73210fb75970d276333f4 Binary files /dev/null and b/api/__pycache__/__init__.cpython-313.pyc differ diff --git a/api/__pycache__/admin.cpython-313.pyc b/api/__pycache__/admin.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9eef8098c65c8baa536f64105e2450e1365ae52a Binary files /dev/null and b/api/__pycache__/admin.cpython-313.pyc differ diff --git a/api/__pycache__/apps.cpython-313.pyc b/api/__pycache__/apps.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6239c0fb9f3d5bf5d10b88a3fa56da66d56ac382 Binary files /dev/null and b/api/__pycache__/apps.cpython-313.pyc differ diff --git a/api/__pycache__/models.cpython-313.pyc b/api/__pycache__/models.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b08ec137dfaaea120ed583dccf8a92f27d44b6d8 Binary files /dev/null and b/api/__pycache__/models.cpython-313.pyc differ diff --git a/api/__pycache__/urls.cpython-313.pyc b/api/__pycache__/urls.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5b4d5b0922a8eb3c879a06f790e6803f41f74a1 Binary files /dev/null and b/api/__pycache__/urls.cpython-313.pyc differ diff --git a/api/__pycache__/utils.cpython-313.pyc b/api/__pycache__/utils.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46f2a4342f35bcf269d7b6734543cc5dbe445af0 Binary files /dev/null and b/api/__pycache__/utils.cpython-313.pyc differ diff --git a/api/__pycache__/views.cpython-313.pyc b/api/__pycache__/views.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..724a595d5b6495f27a63fd6e56ac042e304d7d5c Binary files /dev/null and b/api/__pycache__/views.cpython-313.pyc differ diff --git a/api/admin.py b/api/admin.py index 520914153ea080824a38f09e8008e7f62cfc7d65..11921123f38b6e1d2da4160924532d2893732f21 100644 --- a/api/admin.py +++ b/api/admin.py @@ -1,36 +1,81 @@ from django.contrib import admin -from .models import Bhagat, Event, Attendance, Notification, Region, BhajanCategory, Bhajan +from .models import ( + Bhagat, + Event, + Attendance, + Notification, + Region, + BhajanCategory, + Bhajan, + PushSubscription, + OptionPoll, + Poll, +) from import_export.admin import ImportExportModelAdmin + # Register your models here. class BhagatAdmin(ImportExportModelAdmin): - list_display = ('__str__', 'email', 'region', 'user_type', 'assigned_to') - list_filter = ('region', 'user_type') - search_fields = ('__str__', 'email', 'region', 'user_type', 'assigned_to') + list_display = ( + "get_full_name", + "profileImage", + "email", + "region", + "user_type", + "assigned_to", + ) + list_filter = ("region", "user_type") + search_fields = ( + "get_full_name", + "email", + "region", + "user_type", + "assigned_to", + ) + class RegionAdmin(ImportExportModelAdmin): - list_display = ('name',) + list_display = ("name",) + class BhajanCategoryAdmin(ImportExportModelAdmin): - list_display = ('name', 'link') - search_fields = ('name',) - + list_display = ("name", "icon_image", "link") + search_fields = ("name",) + + class BhajanAdmin(ImportExportModelAdmin): - list_display = ('title', 'title_guj', 'category', 'lyricsBtn') - search_fields = ('title', 'title_guj', 'category__name') - list_filter = ('category',) + list_display = ("title", "title_guj", "category", "lyricsBtn") + search_fields = ("title", "title_guj", "category__name") + list_filter = ("category",) # 'musicPreivew', + class EventAdmin(ImportExportModelAdmin): - list_display = ('title', 'date', 'region', 'is_approved', 'color') - list_filter = ('region', 'is_approved', 'color') - search_fields = ('title', 'date', 'region', 'is_approved', 'color') - list_editable = ('is_approved', 'color') + list_display = ("title", "date", "region", "is_approved", "color") + list_filter = ("region", "is_approved", "color") + search_fields = ("title", "date", "region", "is_approved", "color") + list_editable = ("is_approved", "color") + class NotificationAdmin(ImportExportModelAdmin): - list_display = ('sender', 'title','timestamp', 'notification_type') - list_filter = ('notification_type',) - search_fields = ('sender__first_name', 'title', 'notification_type') + list_display = ("sender", "title", "timestamp", "notification_type") + list_filter = ("notification_type",) + search_fields = ("sender__first_name", "title", "notification_type") + + +class PushSubscriptionAdmin(ImportExportModelAdmin): + list_display = ("user", "endpoint") + + +class OptionPollAdmin(ImportExportModelAdmin): + list_display = ("optionText",) + search_fields = ("optionText",) + + +class PollAdmin(ImportExportModelAdmin): + list_display = ("question", "created_by", "created_at") + search_fields = ("question", "created_by") + admin.site.register(Bhagat, BhagatAdmin) admin.site.register(Region, RegionAdmin) @@ -38,3 +83,6 @@ admin.site.register(BhajanCategory, BhajanCategoryAdmin) admin.site.register(Bhajan, BhajanAdmin) admin.site.register(Event, EventAdmin) admin.site.register(Notification, NotificationAdmin) +admin.site.register(PushSubscription, PushSubscriptionAdmin) +admin.site.register(OptionPoll, OptionPollAdmin) +admin.site.register(Poll, PollAdmin) diff --git a/api/migrations/0016_pushsubscription.py b/api/migrations/0016_pushsubscription.py new file mode 100644 index 0000000000000000000000000000000000000000..c5d142f08f877911291e236931d9dfc9100926f5 --- /dev/null +++ b/api/migrations/0016_pushsubscription.py @@ -0,0 +1,26 @@ +# Generated by Django 5.1.6 on 2025-02-13 21:48 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0015_alter_bhagat_phone'), + ] + + operations = [ + migrations.CreateModel( + name='PushSubscription', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('endpoint', models.URLField(max_length=500)), + ('p256dh', models.CharField(max_length=200)), + ('auth', models.CharField(max_length=100)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/api/migrations/0017_optionpoll_poll.py b/api/migrations/0017_optionpoll_poll.py new file mode 100644 index 0000000000000000000000000000000000000000..0e1759741b0114448a5554e6cb01334c58d1c38f --- /dev/null +++ b/api/migrations/0017_optionpoll_poll.py @@ -0,0 +1,34 @@ +# Generated by Django 5.1.6 on 2025-02-14 17:09 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0016_pushsubscription'), + ] + + operations = [ + migrations.CreateModel( + name='OptionPoll', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('optionText', models.TextField()), + ('voters', models.ManyToManyField(blank=True, related_name='options_voters', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Poll', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('question', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='polls_creator', to=settings.AUTH_USER_MODEL)), + ('options', models.ManyToManyField(blank=True, related_name='polls_options', to='api.optionpoll')), + ('participant', models.ManyToManyField(blank=True, related_name='polls_participant', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/api/migrations/0018_rename_participant_poll_participants.py b/api/migrations/0018_rename_participant_poll_participants.py new file mode 100644 index 0000000000000000000000000000000000000000..1ef7b6cd1fcfa4243d837653668c5d6b7668a21b --- /dev/null +++ b/api/migrations/0018_rename_participant_poll_participants.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-02-14 17:33 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0017_optionpoll_poll'), + ] + + operations = [ + migrations.RenameField( + model_name='poll', + old_name='participant', + new_name='participants', + ), + ] diff --git a/api/migrations/0019_bhajancategory_icon.py b/api/migrations/0019_bhajancategory_icon.py new file mode 100644 index 0000000000000000000000000000000000000000..7fbf8c5096abcd06741ac80743da7b16c7bfb2ce --- /dev/null +++ b/api/migrations/0019_bhajancategory_icon.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-02-15 18:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0018_rename_participant_poll_participants'), + ] + + operations = [ + migrations.AddField( + model_name='bhajancategory', + name='icon', + field=models.URLField(blank=True), + ), + ] diff --git a/api/migrations/0020_alter_bhajan_audio_url.py b/api/migrations/0020_alter_bhajan_audio_url.py new file mode 100644 index 0000000000000000000000000000000000000000..4c63914921ac28c360c3b8dc1578e58783529b61 --- /dev/null +++ b/api/migrations/0020_alter_bhajan_audio_url.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-02-15 22:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0019_bhajancategory_icon'), + ] + + operations = [ + migrations.AlterField( + model_name='bhajan', + name='audio_url', + field=models.CharField(blank=True, max_length=500), + ), + ] diff --git a/api/migrations/__pycache__/0001_initial.cpython-313.pyc b/api/migrations/__pycache__/0001_initial.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9e86d4df92332e469d373b1cfb7f58555ff5854 Binary files /dev/null and b/api/migrations/__pycache__/0001_initial.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0002_alter_bhagat_address_alter_bhagat_birthday_and_more.cpython-313.pyc b/api/migrations/__pycache__/0002_alter_bhagat_address_alter_bhagat_birthday_and_more.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..883e7fd63e0ffed712e2ecf0ff897d7fd48da49f Binary files /dev/null and b/api/migrations/__pycache__/0002_alter_bhagat_address_alter_bhagat_birthday_and_more.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0003_alter_bhagat_address_alter_bhagat_birthday_and_more.cpython-313.pyc b/api/migrations/__pycache__/0003_alter_bhagat_address_alter_bhagat_birthday_and_more.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b9f688d3e55698a4a405d0e2345eb02e1266f24 Binary files /dev/null and b/api/migrations/__pycache__/0003_alter_bhagat_address_alter_bhagat_birthday_and_more.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0004_alter_bhajancategory_svg.cpython-313.pyc b/api/migrations/__pycache__/0004_alter_bhajancategory_svg.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..641d6d7a376a7ac06b561b681a7287b087604894 Binary files /dev/null and b/api/migrations/__pycache__/0004_alter_bhajancategory_svg.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0005_remove_bhajan_lyrics_en_url_and_more.cpython-313.pyc b/api/migrations/__pycache__/0005_remove_bhajan_lyrics_en_url_and_more.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64ec3f9c5ada1d4093bff9ffce3378bdddc7bcd0 Binary files /dev/null and b/api/migrations/__pycache__/0005_remove_bhajan_lyrics_en_url_and_more.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0006_bhajan_isaudio_bhajan_iseng_bhajan_isger_and_more.cpython-313.pyc b/api/migrations/__pycache__/0006_bhajan_isaudio_bhajan_iseng_bhajan_isger_and_more.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9b7372ed77dbe7306be2238172daea50094f1c2 Binary files /dev/null and b/api/migrations/__pycache__/0006_bhajan_isaudio_bhajan_iseng_bhajan_isger_and_more.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0007_remove_bhajancategory_svg.cpython-313.pyc b/api/migrations/__pycache__/0007_remove_bhajancategory_svg.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6dfb18dca71992f92a5ea1b7b3e2878517841028 Binary files /dev/null and b/api/migrations/__pycache__/0007_remove_bhajancategory_svg.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0008_bhajan_bhajanid.cpython-313.pyc b/api/migrations/__pycache__/0008_bhajan_bhajanid.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3a6df89f34a41e32bd5cf7f3724386c0e43a088 Binary files /dev/null and b/api/migrations/__pycache__/0008_bhajan_bhajanid.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0009_event_color_alter_event_created_by_and_more.cpython-313.pyc b/api/migrations/__pycache__/0009_event_color_alter_event_created_by_and_more.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b44923b66eea3d8a561dfe5c6306f74c3baff11 Binary files /dev/null and b/api/migrations/__pycache__/0009_event_color_alter_event_created_by_and_more.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0010_event_time.cpython-313.pyc b/api/migrations/__pycache__/0010_event_time.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c33fcba18af6e8925dab032ffdaed1b89cd1942 Binary files /dev/null and b/api/migrations/__pycache__/0010_event_time.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0011_delete_message.cpython-313.pyc b/api/migrations/__pycache__/0011_delete_message.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb085f8ec7a01a60ca650f127d52c9f64c75cbbc Binary files /dev/null and b/api/migrations/__pycache__/0011_delete_message.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0012_notification_title.cpython-313.pyc b/api/migrations/__pycache__/0012_notification_title.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..962e21b9d4b9b6e62eee6067eaacaa848effd754 Binary files /dev/null and b/api/migrations/__pycache__/0012_notification_title.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0013_bhagat_profile_image_alter_bhagat_user_type_and_more.cpython-313.pyc b/api/migrations/__pycache__/0013_bhagat_profile_image_alter_bhagat_user_type_and_more.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..313eb442abe5284c815af9dbb1a4d9637a0e78b1 Binary files /dev/null and b/api/migrations/__pycache__/0013_bhagat_profile_image_alter_bhagat_user_type_and_more.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0014_rename_address_bhagat_streetname_bhagat_city_and_more.cpython-313.pyc b/api/migrations/__pycache__/0014_rename_address_bhagat_streetname_bhagat_city_and_more.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..922ba45b327dd11d7ef4e9527d80a8072f3b6897 Binary files /dev/null and b/api/migrations/__pycache__/0014_rename_address_bhagat_streetname_bhagat_city_and_more.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0015_alter_bhagat_phone.cpython-313.pyc b/api/migrations/__pycache__/0015_alter_bhagat_phone.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..634859d863ebb102b428d52eb9becaa293c07a5f Binary files /dev/null and b/api/migrations/__pycache__/0015_alter_bhagat_phone.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0016_pushsubscription.cpython-313.pyc b/api/migrations/__pycache__/0016_pushsubscription.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8dcff9beccd3d47ca089d6b3133a27bc9e7b7ecb Binary files /dev/null and b/api/migrations/__pycache__/0016_pushsubscription.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0017_optionpoll_poll.cpython-313.pyc b/api/migrations/__pycache__/0017_optionpoll_poll.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7bbf0653f49273ef2a2a758f7aba675a3b7cb797 Binary files /dev/null and b/api/migrations/__pycache__/0017_optionpoll_poll.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0018_rename_participant_poll_participants.cpython-313.pyc b/api/migrations/__pycache__/0018_rename_participant_poll_participants.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8564d5b85612ef496c6f068726602812e8db634c Binary files /dev/null and b/api/migrations/__pycache__/0018_rename_participant_poll_participants.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0019_bhajancategory_icon.cpython-313.pyc b/api/migrations/__pycache__/0019_bhajancategory_icon.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c8a0ada31f01da58c6799193454aa8df731ccab Binary files /dev/null and b/api/migrations/__pycache__/0019_bhajancategory_icon.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/0020_alter_bhajan_audio_url.cpython-313.pyc b/api/migrations/__pycache__/0020_alter_bhajan_audio_url.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2088727677a3e210fe3622c26860fd57aac64ac Binary files /dev/null and b/api/migrations/__pycache__/0020_alter_bhajan_audio_url.cpython-313.pyc differ diff --git a/api/migrations/__pycache__/__init__.cpython-313.pyc b/api/migrations/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2da4b47cd19389a74f9aabb0762573da8b211a3e Binary files /dev/null and b/api/migrations/__pycache__/__init__.cpython-313.pyc differ diff --git a/api/models.py b/api/models.py index 20ac7e73c93d7239192766476fcae23002731e9b..5671ab355e36ea4d5e118fdfc33431ce8adc3422 100644 --- a/api/models.py +++ b/api/models.py @@ -28,14 +28,21 @@ class Bhagat(AbstractUser): pincode = models.CharField(max_length=10, null=True) assigned_to = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='assigned_users') profile_image = models.URLField(blank=True) - + def __str__(self): return self.first_name + ' ' + self.last_name def save(self, *args, **kwargs): - self.set_password(self.password) + if not self.password.startswith("pbkdf2_sha256"): + self.set_password(self.password) super().save(*args, **kwargs) + def profileImage(self): + return mark_safe('' % self.profile_image) + + def get_full_name(self): + return super().get_full_name() + class Region(models.Model): name = models.CharField(max_length=100) @@ -75,31 +82,36 @@ class Notification(models.Model): class BhajanCategory(models.Model): name = models.CharField(max_length=100) link = models.CharField(max_length=100) - + icon = models.URLField(blank=True) + def __str__(self): return self.name + def icon_image(self): + return mark_safe('' % self.icon) + + class Bhajan(models.Model): - bhajanId = models.IntegerField(blank=True,default=0) - title = models.CharField(max_length=500,blank=True) - title_guj = models.CharField(max_length=500,blank=True) + bhajanId = models.IntegerField(blank=True, default=0) + title = models.CharField(max_length=500, blank=True) + title_guj = models.CharField(max_length=500, blank=True) category = models.ForeignKey(BhajanCategory, on_delete=models.CASCADE) lyrics = models.CharField(max_length=50, blank=True) - audio_url = models.URLField(blank=True) + audio_url = models.CharField(max_length=500, blank=True) isEng = models.BooleanField(default=False) isHnd = models.BooleanField(default=False) isGer = models.BooleanField(default=False) isAudio = models.BooleanField(default=False) - + def __str__(self): return self.title - + def musicPreivew(self): if self.isAudio: return mark_safe('' % self.audio_url) else: return 'No Audio Available' - + def lyricsBtn(self): # i have four languages in my bhajan so add them all as buttons and show them on click languages = [["","GUJ"]] @@ -113,4 +125,37 @@ class Bhajan(models.Model): for lang in languages: html += '
  • '+(lang[1])+'
  • ' html += '' - return mark_safe(html) \ No newline at end of file + return mark_safe(html) + + +class PushSubscription(models.Model): + user = models.ForeignKey(Bhagat, on_delete=models.CASCADE, null=True) + endpoint = models.URLField(max_length=500) + p256dh = models.CharField(max_length=200) + auth = models.CharField(max_length=100) + created_at = models.DateTimeField(auto_now_add=True) + + +class OptionPoll(models.Model): + optionText = models.TextField() + voters = models.ManyToManyField(Bhagat, related_name="options_voters", blank=True) + + def __str__(self): + return self.optionText + + +class Poll(models.Model): + question = models.TextField() + options = models.ManyToManyField( + OptionPoll, related_name="polls_options", blank=True + ) + participants = models.ManyToManyField( + Bhagat, related_name="polls_participant", blank=True + ) + created_by = models.ForeignKey( + Bhagat, on_delete=models.CASCADE, related_name="polls_creator" + ) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.question diff --git a/api/urls.py b/api/urls.py index 187a4ab58372ff00c3d92baa25171d40132d163f..275b7beabebc3d5827b6f52a3c292684dcedf0a2 100644 --- a/api/urls.py +++ b/api/urls.py @@ -3,19 +3,25 @@ from . import views from rest_framework_simplejwt.views import TokenRefreshView urlpatterns = [ - path('login/', views.login, name='login'), - path('logout/', views.logout, name='logout'), - path('get-user-profile/', views.get_user_profile, name='get_user_profile'), - path('profile-updater/', views.profile_updater, name='profile_updater'), - path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), - - path('dataEntry/', views.dataEntry, name='dataEntry'), - path('send-notification/', views.send_notification, name='send_notification'), - - path('bhajan-category-list/', views.bhajanCategoryList, name='bhajanCategoryList'), - path('bhajan-detail/', views.bhajanDetail, name='bhajanDetail'), - path('event-list/', views.eventList, name='eventList'), - path('notification/', views.notification, name='notification'), - - path('bhakto-list/', views.bhaktoList, name='bhaktoList'), + path("login/", views.login, name="login"), + path("logout/", views.logout, name="logout"), + path("get-user-profile/", views.get_user_profile, name="get_user_profile"), + path("profile-updater/", views.profile_updater, name="profile_updater"), + path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), + path("dataEntry/", views.dataEntry, name="dataEntry"), + path("send-notification/", views.send_notification, name="send_notification"), + path("bhajan-list/", views.bhajanList, name="bhajanList"), + path("bhajan-category-list/", views.bhajanCategoryList, name="bhajanCategoryList"), + path( + "bhajan-detail//", views.bhajanDetail, name="bhajanDetail" + ), + path("event-list/", views.eventList, name="eventList"), + path("bhakto-list/", views.bhaktoList, name="bhaktoList"), + path("notification/", views.notification, name="notification"), + path("push-subscription/", views.save_push_subscription, name="push_subscription"), + path("send-otp/", views.send_otp, name="send_otp"), + path("verify-otp/", views.verify_otp, name="verify_otp"), + path("change-password/", views.change_password, name="change_password"), + path("polls/", views.polls, name="polls"), + path("poll-voters/", views.voterList, name="voterList"), ] diff --git a/api/views.py b/api/views.py index 09f138b0476eba6cf29eaa7ba34380141053f213..08fd800bf4054315cc612b9e7ca0c96b44a247d7 100644 --- a/api/views.py +++ b/api/views.py @@ -5,8 +5,20 @@ from django.http import JsonResponse, HttpResponse from django.views.decorators.http import require_POST from django.utils import timezone import json -from .models import Bhagat, Event, Attendance, Notification, Region, BhajanCategory, Bhajan +from .models import ( + Bhagat, + Event, + Attendance, + PushSubscription, + Notification, + Region, + BhajanCategory, + Bhajan, + OptionPoll, + Poll, +) from django.conf import settings +from django.core import serializers import requests from rest_framework.decorators import api_view, permission_classes @@ -14,6 +26,7 @@ from rest_framework.permissions import AllowAny from rest_framework.response import Response from .utils import jwt_required from rest_framework_simplejwt.tokens import RefreshToken +from pywebpush import webpush, WebPushException def gCaptchaVerifer(token): @@ -24,15 +37,15 @@ def gCaptchaVerifer(token): def is_superadmin(user): - return user.user_type == 'superadmin' + return user.user_type == "superadmin" def is_regionadmin(user): - return user.user_type == 'regionadmin' + return user.user_type == "regionadmin" def is_monitor(user): - return user.user_type == 'monitor' + return user.user_type == "monitor" def dataEntry(request): @@ -57,52 +70,78 @@ def dataEntry(request): def bhajanCategoryList(request): categories = BhajanCategory.objects.all() - bhajans = Bhajan.objects.all() - bhajanArr = [] - for bhajan in bhajans: - bhajanArr.append({ - "id": bhajan.bhajanId, - "title": bhajan.title, - "title_guj": bhajan.title_guj, - "category": bhajan.category.name, - "lyrics": bhajan.lyrics, - "audio_url": bhajan.audio_url, - "isEng": bhajan.isEng, - "isHnd": bhajan.isHnd, - "isGer": bhajan.isGer, - "isAudio": bhajan.isAudio - }) categoryArr = [] for category in categories: - categoryArr.append({ - "name": category.name, - "link": category.link - }) - lyricsBase = "https://huggingface.co/spaces/thejagstudio/MusicStore/raw/main/HTML Files/" + categoryArr.append( + {"name": category.name, "link": category.link, "icon": category.icon} + ) + lyricsBase = ( + "https://huggingface.co/spaces/thejagstudio/MusicStore/raw/main/HTML Files/" + ) + audioBase = "https://huggingface.co/spaces/thejagstudio/MusicStore/resolve/main/Bhajan Audio/" + return JsonResponse( + {"categories": categoryArr, "lyricsBase": lyricsBase, "audioBase": audioBase} + ) + + +def bhajanList(request, catLink): + if catLink == "all-kirtan": + bhajans = Bhajan.objects.all() + category = "All Kirtan" + else: + bhajans = Bhajan.objects.filter(category__link=catLink) + category = BhajanCategory.objects.get(link=catLink).name + bhajanArr = [] + for bhajan in bhajans: + bhajanArr.append( + { + "id": bhajan.bhajanId, + "title": bhajan.title, + "title_guj": bhajan.title_guj, + "lyrics": bhajan.lyrics, + "audio_url": bhajan.audio_url, + "isEng": bhajan.isEng, + "isHnd": bhajan.isHnd, + "isGer": bhajan.isGer, + "isAudio": bhajan.isAudio, + } + ) + + lyricsBase = ( + "https://huggingface.co/spaces/thejagstudio/MusicStore/raw/main/HTML Files/" + ) audioBase = "https://huggingface.co/spaces/thejagstudio/MusicStore/resolve/main/Bhajan Audio/" - return JsonResponse({"categories": categoryArr, "bhajans": bhajanArr, "lyricsBase": lyricsBase, "audioBase": audioBase}) + return JsonResponse( + { + "bhajans": bhajanArr, + "lyricsBase": lyricsBase, + "audioBase": audioBase, + "category": category, + } + ) -def bhajanDetail(request, id): - bhajan = Bhajan.objects.get(bhajanId=id) +def bhajanDetail(request, catLink, id): + bhajan = Bhajan.objects.get(bhajanId=id, category__link=catLink) if bhajan is None: return JsonResponse({"error": "Bhajan not found"}) else: - return JsonResponse({ - "id": bhajan.bhajanId, - "title": bhajan.title, - "title_guj": bhajan.title_guj, - "category": bhajan.category.name, - "lyrics": bhajan.lyrics, - "audio_url": bhajan.audio_url, - "isEng": bhajan.isEng, - "isHnd": bhajan.isHnd, - "isGer": bhajan.isGer, - "isAudio": bhajan.isAudio, - "lyricsBase": "https://huggingface.co/spaces/thejagstudio/MusicStore/raw/main/HTML Files/", - "audioBase": "https://huggingface.co/spaces/thejagstudio/MusicStore/resolve/main/Bhajan Audio/" - }) - return HttpResponse("Bhajan Detail Page") + return JsonResponse( + { + "id": bhajan.bhajanId, + "title": bhajan.title, + "title_guj": bhajan.title_guj, + "category": bhajan.category.name, + "lyrics": bhajan.lyrics, + "audio_url": bhajan.audio_url, + "isEng": bhajan.isEng, + "isHnd": bhajan.isHnd, + "isGer": bhajan.isGer, + "isAudio": bhajan.isAudio, + "lyricsBase": "https://huggingface.co/spaces/thejagstudio/MusicStore/raw/main/HTML Files/", + "audioBase": "https://huggingface.co/spaces/thejagstudio/MusicStore/resolve/main/Bhajan Audio/", + } + ) def eventList(request): @@ -110,34 +149,45 @@ def eventList(request): eventArr = [] for event in events: # convert date to Sept 26,2024 | 8:30 - 9:30 - dateFormatted = event.date.strftime("%b %d, %Y") + " | " + event.date.strftime("%I:%M %p") + " - " + event.time.strftime("%I:%M %p") - eventArr.append({ - "title": event.title, - "description": event.description, - "date": dateFormatted, - "day": int(event.date.strftime("%d")), - "month": int(event.date.strftime("%m")), - "year": int(event.date.strftime("%Y")), - "created_by": event.created_by.__str__(), - "region": event.region.name, - "is_approved": event.is_approved, - "color": event.color - }) + dateFormatted = ( + event.date.strftime("%b %d, %Y") + + " | " + + event.date.strftime("%I:%M %p") + + " - " + + event.time.strftime("%I:%M %p") + ) + eventArr.append( + { + "title": event.title, + "description": event.description, + "date": dateFormatted, + "day": int(event.date.strftime("%d")), + "month": int(event.date.strftime("%m")), + "year": int(event.date.strftime("%Y")), + "created_by": event.created_by.__str__(), + "region": event.region.name, + "is_approved": event.is_approved, + "color": event.color, + } + ) return JsonResponse({"events": eventArr}) + @jwt_required() def notification(request): notifications = Notification.objects.all() notificationArr = [] for notification in notifications: - notificationArr.append({ - "sender": notification.sender.__str__(), - "category": notification.sender.user_type, - "title": notification.title, - "content": notification.content, - "timestamp": notification.timestamp.strftime("%b %d, %Y | %I:%M %p"), - "notification_type": notification.notification_type - }) + notificationArr.append( + { + "sender": notification.sender.__str__(), + "category": notification.sender.user_type, + "title": notification.title, + "content": notification.content, + "timestamp": notification.timestamp.strftime("%b %d, %Y | %I:%M %p"), + "notification_type": notification.notification_type, + } + ) return JsonResponse({"notifications": notificationArr}) @@ -145,48 +195,55 @@ def notification(request): @csrf_exempt @jwt_required() def send_notification(request): - if request.method == 'POST': - content = request.POST.get('content') - recipient_type = request.POST.get('recipient_type') - if recipient_type == 'all': - recipients = Bhagat.objects.all() - elif recipient_type == 'monitors': - recipients = Bhagat.objects.filter(user_type='monitor') - elif recipient_type == 'regionadmins': - recipients = Bhagat.objects.filter(user_type='regionadmin') + if request.method == "POST": + content = request.POST.get("content") + recipient_type = request.POST.get("recipient_type") - notification = Notification.objects.create(sender=request.user, content=content, notification_type='custom') - notification.recipients.set(recipients) + notification = Notification.objects.create( + sender=request.user, content=content, notification_type="custom" + ) + + # Send web push notifications + subscriptions = PushSubscription.objects.all() + for subscription in subscriptions: + send_push_notification( + subscription, + { + "title": "New Notification", + "content": content, + "url": "/notifications", + }, + ) - return redirect('notifications') + return JsonResponse({"status": "success"}) + return JsonResponse({"status": "error"}) def birthday_notifications(): today = timezone.now().date() - birthday_users = Bhagat.objects.filter(birthday__month=today.month, birthday__day=today.day) + birthday_users = Bhagat.objects.filter( + birthday__month=today.month, birthday__day=today.day + ) for user in birthday_users: notification = Notification.objects.create( - sender=Bhagat.objects.get(user_type='superadmin'), + sender=Bhagat.objects.get(user_type="superadmin"), content=f"Happy Birthday to {user.get_full_name()}!", - notification_type='birthday' + notification_type="birthday", ) notification.recipients.set(Bhagat.objects.all()) @csrf_exempt def login(request): - if request.method == 'POST': - username = request.POST.get('username') - password = request.POST.get('password') - captcha_response = request.POST.get('captcha_response') + if request.method == "POST": + username = request.POST.get("username") + password = request.POST.get("password") + captcha_response = request.POST.get("captcha_response") # Verify captcha result = gCaptchaVerifer(captcha_response) if not result.get("success"): - return JsonResponse({ - "error": "Invalid Captcha", - "status": "error" - }) + return JsonResponse({"error": "Invalid Captcha", "status": "error"}) # Authenticate user user = Bhagat.objects.filter(username=username).first() @@ -194,145 +251,131 @@ def login(request): # Generate tokens refresh = RefreshToken.for_user(user) - return JsonResponse({ - "status": "success", - "tokens": { - "access_token": str(refresh.access_token), - "refresh_token": str(refresh) - }, - "user": { - "id": user.id, - "username": user.username, - "first_name": user.first_name, - "last_name": user.last_name, - "email": user.email, - "phone": user.phone, - "region": user.region.name, - "user_type": user.user_type, - "profile_image": user.profile_image + return JsonResponse( + { + "status": "success", + "tokens": { + "access_token": str(refresh.access_token), + "refresh_token": str(refresh), + }, + "user": { + "id": user.id, + "username": user.username, + "first_name": user.first_name, + "last_name": user.last_name, + "email": user.email, + "phone": user.phone, + "region": user.region.name, + "user_type": user.user_type, + "profile_image": user.profile_image, + }, } - }) - - return JsonResponse({ - "error": "Invalid credentials", - "status": "error" - }) + ) - return JsonResponse({ - "error": "Invalid Method", - "status": "error" - }) + return JsonResponse({"error": "Invalid credentials", "status": "error"}) + return JsonResponse({"error": "Invalid Method", "status": "error"}) @csrf_exempt @jwt_required() def logout(request): - if request.method == 'POST': - refresh_token = request.POST.get('refresh_token') + if request.method == "POST": + refresh_token = request.POST.get("refresh_token") if not refresh_token: - return JsonResponse({ - 'error': 'Refresh token is required', - 'status': 'error' - }) + return JsonResponse( + {"error": "Refresh token is required", "status": "error"} + ) else: try: refresh = RefreshToken(refresh_token) refresh.blacklist() - return JsonResponse({ - 'status': 'success', - 'message': 'Successfully logged out' - }) - except TokenError: - return JsonResponse({ - "error": "Invalid token", - "status": "error" - }) - return JsonResponse({ - "status": "error", - "error": "Invalid Method" - }) + return JsonResponse( + {"status": "success", "message": "Successfully logged out"} + ) + except Exception as e: + return JsonResponse( + {"error": "Invalid token | " + str(e), "status": "error"} + ) + return JsonResponse({"status": "error", "error": "Invalid Method"}) @jwt_required() def get_user_profile(request): try: user = request.user - return JsonResponse({ - "status": "success", - "user": { - "id": user.id, - "username": user.username, - "first_name": user.first_name, - "last_name": user.last_name, - "email": user.email, - "phone": user.phone, - "region": user.region.name, - "user_type": user.user_type, - "profile_image": user.profile_image + return JsonResponse( + { + "status": "success", + "user": { + "id": user.id, + "username": user.username, + "first_name": user.first_name, + "last_name": user.last_name, + "email": user.email, + "phone": user.phone, + "region": user.region.name, + "user_type": user.user_type, + "profile_image": user.profile_image, + }, } - }) + ) except Exception as e: - return JsonResponse({ - "status": "error", - "error": str(e) - }) + return JsonResponse({"status": "error", "error": str(e)}) + @csrf_exempt @jwt_required() def profile_updater(request): - if request.method == 'POST': + if request.method == "POST": try: user = request.user - first_name = request.POST.get('first_name') + first_name = request.POST.get("first_name") if first_name: user.first_name = first_name - last_name = request.POST.get('last_name') + last_name = request.POST.get("last_name") if last_name: user.last_name = last_name - email = request.POST.get('email') + email = request.POST.get("email") if email: user.email = email - phone = request.POST.get('phone') + phone = request.POST.get("phone") if phone: user.phone = phone - region_name = request.POST.get('region') + region_name = request.POST.get("region") if region_name: user.region = Region.objects.get(name=region_name) - birth_date = request.POST.get('birth_date') + birth_date = request.POST.get("birth_date") if birth_date: user.birthday = birth_date - street_name = request.POST.get('street_name') + street_name = request.POST.get("street_name") if street_name: user.streetName = street_name - pincode = request.POST.get('pincode') + pincode = request.POST.get("pincode") if pincode: user.pincode = pincode - city = request.POST.get('city') + city = request.POST.get("city") if city: user.city = city - state = request.POST.get('state') + state = request.POST.get("state") if state: user.state = state - country = request.POST.get('country') + country = request.POST.get("country") if country: user.country = country - profile_image = request.POST.get('profile_image') + profile_image = request.POST.get("profile_image") if profile_image: user.profile_image = profile_image user.save() - return JsonResponse({ - "status": "success", - "message": "Profile updated successfully" - }) + return JsonResponse( + {"status": "success", "message": "Profile updated successfully"} + ) except Exception as e: - return JsonResponse({ - "status": "error", - "error": str(e) - }) + return JsonResponse({"status": "error", "error": str(e)}) else: user = request.user - data= { + regions = Region.objects.all() + data = { "first_name": user.first_name, "last_name": user.last_name, "email": user.email, @@ -344,12 +387,15 @@ def profile_updater(request): "city": user.city, "state": user.state, "country": user.country, - "profile_image": user.profile_image + "profile_image": user.profile_image, } - return JsonResponse({ - "status": "success", - "user": data - }) + return JsonResponse( + { + "status": "success", + "regions": [region.name for region in regions], + "user": data, + } + ) @jwt_required() @@ -358,12 +404,229 @@ def bhaktoList(request): bhaktos = Bhagat.objects.filter(assigned_to=current_user).all() bhaktoArr = [] for bhakto in bhaktos: - bhaktoArr.append({ - "id": bhakto.id, - "first_name": bhakto.first_name, - "last_name": bhakto.last_name, - "region": bhakto.region.name, - "user_type": bhakto.user_type, - "profile_image": bhakto.profile_image - }) - return JsonResponse({"bhaktos": bhaktoArr}) \ No newline at end of file + bhaktoArr.append( + { + "id": bhakto.id, + "first_name": bhakto.first_name, + "last_name": bhakto.last_name, + "region": bhakto.region.name, + "user_type": bhakto.user_type, + "profile_image": bhakto.profile_image, + } + ) + return JsonResponse({"bhaktos": bhaktoArr}) + + +@api_view(["POST"]) +@permission_classes([AllowAny]) +def send_otp(request): + try: + data = json.loads(request.body) + phone = data.get("phone") + + if not phone: + return JsonResponse( + {"status": "error", "error": "Phone number is required"} + ) + + # Check if user exists + user = Bhagat.objects.filter(phone=phone).first() + if not user: + return JsonResponse( + {"status": "error", "error": "No account found with this phone number"} + ) + + # Generate dummy OTP (in production, use proper OTP generation and SMS service) + otp = "123456" # Dummy OTP for testing + print(f"Generated OTP for {phone}: {otp}") # This simulates sending OTP + + # In production, store OTP with timestamp in database or cache + # For now, we'll just return success + return JsonResponse({"status": "success", "message": "OTP sent successfully"}) + + except Exception as e: + return JsonResponse({"status": "error", "error": str(e)}) + + +@api_view(["POST"]) +@permission_classes([AllowAny]) +def verify_otp(request): + try: + data = json.loads(request.body) + phone = data.get("phone") + otp = data.get("otp") + + if not phone or not otp: + return JsonResponse( + {"status": "error", "error": "Phone number and OTP are required"} + ) + + # For demo purposes, accept any 6-digit OTP + if otp == "123456": # Dummy verification + return JsonResponse( + {"status": "success", "message": "OTP verified successfully"} + ) + + return JsonResponse({"status": "error", "error": "Invalid OTP"}) + + except Exception as e: + return JsonResponse({"status": "error", "error": str(e)}) + + +@api_view(["POST"]) +@jwt_required() +@csrf_exempt +@permission_classes([AllowAny]) +def change_password(request): + try: + data = json.loads(request.body) + new_password = data.get("new_password") + + if not new_password: + return JsonResponse( + { + "status": "error", + "error": "Phone number and new password are required", + } + ) + + # Update user's password + user = request.user + if not user: + return JsonResponse({"status": "error", "error": "User not found"}) + + user.password = new_password + user.save() + + return JsonResponse( + {"status": "success", "message": "Password changed successfully"} + ) + + except Exception as e: + return JsonResponse({"status": "error", "error": str(e)}) + + +@jwt_required() +@api_view(["POST"]) +@csrf_exempt +@permission_classes([AllowAny]) +def save_push_subscription(request): + try: + subscription_data = json.loads(request.body) + user = request.user + pushUser = PushSubscription.objects.filter(user=user).first() + if pushUser: + pushUser.endpoint = subscription_data["endpoint"] + pushUser.p256dh = subscription_data["keys"]["p256dh"] + pushUser.auth = subscription_data["keys"]["auth"] + pushUser.save() + else: + PushSubscription.objects.create( + user=user, + endpoint=subscription_data["endpoint"], + p256dh=subscription_data["keys"]["p256dh"], + auth=subscription_data["keys"]["auth"], + ) + return JsonResponse({"status": "success"}) + except Exception as e: + return JsonResponse({"status": "error", "message": str(e)}) + + +def send_push_notification(subscription, message): + try: + webpush( + subscription_info={ + "endpoint": subscription.endpoint, + "keys": {"p256dh": subscription.p256dh, "auth": subscription.auth}, + }, + data=json.dumps(message), + vapid_private_key=settings.WEBPUSH_SETTINGS["VAPID_PRIVATE_KEY"], + vapid_claims={ + "sub": f"mailto:{settings.WEBPUSH_SETTINGS['VAPID_ADMIN_EMAIL']}" + }, + ) + except WebPushException as e: + print(f"Web push failed: {e}") + + +@api_view(["GET", "POST"]) +@jwt_required() +@csrf_exempt +@permission_classes([AllowAny]) +def polls(request): + if request.method == "GET": + user = request.user + polls = Poll.objects.filter(participants=user) + pollArr = [] + for poll in polls: + tempPoll = {} + tempPoll["id"] = poll.id + tempPoll["question"] = poll.question + tempPoll["options"] = [] + for option in poll.options.all(): + tempOption = {} + tempOption["id"] = option.id + tempOption["optionText"] = option.optionText + tempOption["count"] = option.voters.all().count() + tempOption["precentage"] = ( + option.voters.all().count() / poll.participants.all().count() + ) * 100 + tempOption["voters"] = [] + for voter in option.voters.all()[:2]: + tempOption["voters"].append( + { + "id": voter.profile_image, + "first_name": voter.first_name, + "last_name": voter.last_name, + "profile_image": voter.profile_image, + } + ) + tempPoll["options"].append(tempOption) + tempPoll["created_by"] = { + "id": poll.created_by.profile_image, + "first_name": poll.created_by.first_name, + "last_name": poll.created_by.last_name, + "profile_image": poll.created_by.profile_image, + } + tempPoll["created_at"] = poll.created_at + pollArr.append(tempPoll) + return JsonResponse({"data": pollArr}) + if request.method == "POST": + data = json.loads(request.body) + user = request.user + poll = Poll.objects.get(id=id) + option = OptionPoll.objects.get(id=data.get("option")) + option.votes.add(user) + return JsonResponse( + {"status": "success", "message": "Vote submitted successfully"} + ) + + +@api_view(["GET"]) +@jwt_required() +@permission_classes([AllowAny]) +def voterList(request, id): + poll = Poll.objects.filter(participants=user).get(id=id) + if not poll: + return JsonResponse( + {"error": "Poll may not exist or you may not have access to it"} + ) + else: + user = request.user + options = poll.options.all() + optionsList = [] + for option in options: + tempOption = {} + tempOption["id"] = option.id + tempOption["optionText"] = option.optionText + tempOption["voters"] = [] + for voter in option.voters.all(): + tempOption["voters"].append( + { + "id": voter.profile_image, + "first_name": voter.first_name, + "last_name": voter.last_name, + "profile_image": voter.profile_image, + } + ) + return JsonResponse({"data": optionsList}) diff --git a/downloads/1.jpg b/downloads/1.jpg deleted file mode 100644 index 5e78906f4ee0039e69fce344ec0c6c97d5683c08..0000000000000000000000000000000000000000 --- a/downloads/1.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:69bdb2fd55e4c88d905dfb9f63ef7eb8134656b4da7644ef2d5928cbd18f202d -size 2408828 diff --git a/downloads/10.png b/downloads/10.png deleted file mode 100644 index 3886edcd5537740e2a779e2daba5e36cef6fece6..0000000000000000000000000000000000000000 Binary files a/downloads/10.png and /dev/null differ diff --git a/downloads/100.png b/downloads/100.png deleted file mode 100644 index e2e55babc9e85b0091d096d5c56eebe14cfa7287..0000000000000000000000000000000000000000 --- a/downloads/100.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6dda40896ee605bcd42a981f5c00ef64b603aa4c5c51953634f2d403d222ba1e -size 3054323 diff --git a/downloads/101.png b/downloads/101.png deleted file mode 100644 index 5632f943eb33ff8739e38817eac81fdd522dd0a5..0000000000000000000000000000000000000000 --- a/downloads/101.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6543731df314943327c1c94bf1dacc0a440902d694aba759d1453721e3b4d842 -size 1584045 diff --git a/downloads/102.png b/downloads/102.png deleted file mode 100644 index fe5de22f8338da90bf7ca4cfcbcc2ca250d25efb..0000000000000000000000000000000000000000 --- a/downloads/102.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:119e7c81a0a754d57cab878af98aed096af735c1bbd09b1b7c829d5b9250ffea -size 1713007 diff --git a/downloads/103.png b/downloads/103.png deleted file mode 100644 index 72cb3af66753fc4ad9c5c3425e40fb73d0a20457..0000000000000000000000000000000000000000 --- a/downloads/103.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0f0148cb61fdc0c7da26af9e562135aa33b05bcb3a91431af24336962085953 -size 2010696 diff --git a/downloads/104.png b/downloads/104.png deleted file mode 100644 index 44837d96963ac54df8babe8c08ccd64cc0043e66..0000000000000000000000000000000000000000 --- a/downloads/104.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8961becfc68a44c83376286770475c64a35fe98f4698e81abe29bdbc84e891c3 -size 2006656 diff --git a/downloads/105.png b/downloads/105.png deleted file mode 100644 index afef1151bc834e35caccfc4843b9c3531db5914b..0000000000000000000000000000000000000000 --- a/downloads/105.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:41c05b54b83cfc087fba7690f3b928a2e37f8df400c42e63d8663af06cfee209 -size 1395996 diff --git a/downloads/106.png b/downloads/106.png deleted file mode 100644 index e7789327b38e311c87a85a1f3aabd18ac5ddfe27..0000000000000000000000000000000000000000 --- a/downloads/106.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:82ca9d736f44f3c8e427385a534213dea82d28adf7a70edbc8ce5ea25631a225 -size 1931890 diff --git a/downloads/107.png b/downloads/107.png deleted file mode 100644 index 92a63b8961013cce9389e6d8ea60c22bcef551ff..0000000000000000000000000000000000000000 --- a/downloads/107.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c275fb498192252b829928b718d7fdb58fdaa0ba03a601dddc171cbbed7d7f3 -size 2083249 diff --git a/downloads/108.png b/downloads/108.png deleted file mode 100644 index 609c5a7eb9675d771c38345c4cab1c560f9ddcd9..0000000000000000000000000000000000000000 --- a/downloads/108.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cef9b982c3d20b82c0e71c9bd3be5195421d8a5816b8f4032026e3ce0bb4700c -size 2034266 diff --git a/downloads/109.jpg b/downloads/109.jpg deleted file mode 100644 index c6db660d7e1bc789c3de4c594599c1b53db17b3f..0000000000000000000000000000000000000000 Binary files a/downloads/109.jpg and /dev/null differ diff --git a/downloads/11.png b/downloads/11.png deleted file mode 100644 index 9454ebb6694d24dcff427d503aebb1a66fff0764..0000000000000000000000000000000000000000 --- a/downloads/11.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3331a1427f8656575af1b98bb804b8366bb01d45e83589e066d8a0eeb1eff544 -size 1317829 diff --git a/downloads/110.jpg b/downloads/110.jpg deleted file mode 100644 index 7a4d110f56b6d8b5f057e6aa0587ca0d714fccad..0000000000000000000000000000000000000000 --- a/downloads/110.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6ed0a57057927f42b2aae4459da7bf7b31796426d504561cb428d08eb5e18e91 -size 1284419 diff --git a/downloads/111.jpg b/downloads/111.jpg deleted file mode 100644 index e5a4d882cf7d96092ba25766cbe2c26bcbbcab64..0000000000000000000000000000000000000000 Binary files a/downloads/111.jpg and /dev/null differ diff --git a/downloads/112.jpg b/downloads/112.jpg deleted file mode 100644 index 9848568bf3b52239f4c7d885eb845b722945842f..0000000000000000000000000000000000000000 --- a/downloads/112.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae61ea46e92f9964f6ced6bbec4f861ddabc6d747103126c406ceec489218e7d -size 1035179 diff --git a/downloads/113.jpg b/downloads/113.jpg deleted file mode 100644 index b733968ce3f7a1f60c24adee019082c9e55d6895..0000000000000000000000000000000000000000 Binary files a/downloads/113.jpg and /dev/null differ diff --git a/downloads/114.jpg b/downloads/114.jpg deleted file mode 100644 index 9b3a9ad9255135ef9101395a8be75c7bd7dfd20e..0000000000000000000000000000000000000000 Binary files a/downloads/114.jpg and /dev/null differ diff --git a/downloads/115.jpg b/downloads/115.jpg deleted file mode 100644 index f352637e253dc4c1b9d976af22c91d58e7389721..0000000000000000000000000000000000000000 Binary files a/downloads/115.jpg and /dev/null differ diff --git a/downloads/116.jpg b/downloads/116.jpg deleted file mode 100644 index 18c43b3d63e0fdbef27ae14ab91095f459d98712..0000000000000000000000000000000000000000 --- a/downloads/116.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8b61684922edac91874812c9ff40035380c3d991e3fc6c5f90ad7d51adbcfd89 -size 1816427 diff --git a/downloads/117.jpg b/downloads/117.jpg deleted file mode 100644 index 3311d13385e5d806c674741ec6634558f87c8b23..0000000000000000000000000000000000000000 Binary files a/downloads/117.jpg and /dev/null differ diff --git a/downloads/118.jpg b/downloads/118.jpg deleted file mode 100644 index 9d012f9de85b3d2b19218118beccb292c19d55a5..0000000000000000000000000000000000000000 Binary files a/downloads/118.jpg and /dev/null differ diff --git a/downloads/119.jpg b/downloads/119.jpg deleted file mode 100644 index 24f9e65d60685dcdbb47948e91f280112e9b3e1c..0000000000000000000000000000000000000000 Binary files a/downloads/119.jpg and /dev/null differ diff --git a/downloads/12.png b/downloads/12.png deleted file mode 100644 index 0cd2b6ec328998837bd9824841ab7122dbbd15e9..0000000000000000000000000000000000000000 Binary files a/downloads/12.png and /dev/null differ diff --git a/downloads/120.jpg b/downloads/120.jpg deleted file mode 100644 index ced9ac2c1c949d81bcbe62a5a0d734d236bb592c..0000000000000000000000000000000000000000 Binary files a/downloads/120.jpg and /dev/null differ diff --git a/downloads/121.jpg b/downloads/121.jpg deleted file mode 100644 index 91c36916c64d2ddcc1d2aa2001923099c83b52af..0000000000000000000000000000000000000000 Binary files a/downloads/121.jpg and /dev/null differ diff --git a/downloads/122.jpg b/downloads/122.jpg deleted file mode 100644 index 43a1482353c2635e7ffeb5f35ddbcc667b3b7c2b..0000000000000000000000000000000000000000 Binary files a/downloads/122.jpg and /dev/null differ diff --git a/downloads/123.jpg b/downloads/123.jpg deleted file mode 100644 index b3a84164516484f1df0f0250b0a3eee29ec389e2..0000000000000000000000000000000000000000 Binary files a/downloads/123.jpg and /dev/null differ diff --git a/downloads/124.jpg b/downloads/124.jpg deleted file mode 100644 index 02338e48a59290dbd85bcadc19eccb7ea523ec5e..0000000000000000000000000000000000000000 Binary files a/downloads/124.jpg and /dev/null differ diff --git a/downloads/125.jpg b/downloads/125.jpg deleted file mode 100644 index a5bc4379a13339e4ab79ff3c8f1ee4cd2b3f60bd..0000000000000000000000000000000000000000 --- a/downloads/125.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e494c8cdfb8b2abef770763efc6aee8b73993c0d3d3f7e8c0d443306056c0b16 -size 1240043 diff --git a/downloads/126.jpg b/downloads/126.jpg deleted file mode 100644 index 35f95c888bdea74c862f113d035f20ffb5c76c9c..0000000000000000000000000000000000000000 Binary files a/downloads/126.jpg and /dev/null differ diff --git a/downloads/127.jpg b/downloads/127.jpg deleted file mode 100644 index ab56289f9d439c420314d56921495d8f9373dee5..0000000000000000000000000000000000000000 --- a/downloads/127.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:52fb55da1dd21c0a9d6038afb2bb6515c695be040eed306d86932eecf41fb5d1 -size 1099637 diff --git a/downloads/128.jpg b/downloads/128.jpg deleted file mode 100644 index 29a79d4b0c87ee33c159d6282327328d320c4a0b..0000000000000000000000000000000000000000 Binary files a/downloads/128.jpg and /dev/null differ diff --git a/downloads/129.jpg b/downloads/129.jpg deleted file mode 100644 index 1b3b8e3b551e1d2c6f6cdbc47ad4a5d73ff2bd16..0000000000000000000000000000000000000000 Binary files a/downloads/129.jpg and /dev/null differ diff --git a/downloads/13.png b/downloads/13.png deleted file mode 100644 index 883a975ae1cb3da731da0ebf5fa1eb4a20f40fe9..0000000000000000000000000000000000000000 --- a/downloads/13.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13c28fbfa93b11454afeaab368db86a65f9b35ee66f216e5c384aaa0f9b4f160 -size 1077629 diff --git a/downloads/130.jpg b/downloads/130.jpg deleted file mode 100644 index fcb08df8a20e9f88b3e76407c60ad70f794031c7..0000000000000000000000000000000000000000 --- a/downloads/130.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c89f53fcf78cbf448b993a4ee2250665e657266b9d3cab8706ee464995d1f62a -size 1118299 diff --git a/downloads/131.jpg b/downloads/131.jpg deleted file mode 100644 index c25a724078612a2a93fca4a5aa2b6a1732c38e67..0000000000000000000000000000000000000000 Binary files a/downloads/131.jpg and /dev/null differ diff --git a/downloads/132.jpg b/downloads/132.jpg deleted file mode 100644 index a233943f97fef824cada51f707e6d3e548e18e76..0000000000000000000000000000000000000000 Binary files a/downloads/132.jpg and /dev/null differ diff --git a/downloads/133.jpg b/downloads/133.jpg deleted file mode 100644 index c2d342c5e2ac93652f7c32c031e3f4855e6110d6..0000000000000000000000000000000000000000 Binary files a/downloads/133.jpg and /dev/null differ diff --git a/downloads/134.jpg b/downloads/134.jpg deleted file mode 100644 index b73056e284cd4012a15671c939d6f2af3ae0208f..0000000000000000000000000000000000000000 --- a/downloads/134.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd0d7539a6b92bf82296ed0716b3ffa212e51d8724e69d883c30eef47e58ea3d -size 1273644 diff --git a/downloads/135.jpg b/downloads/135.jpg deleted file mode 100644 index 887cbeea58f65608725a2bfab674b41eaadd3300..0000000000000000000000000000000000000000 Binary files a/downloads/135.jpg and /dev/null differ diff --git a/downloads/136.jpg b/downloads/136.jpg deleted file mode 100644 index 82dde44d0e727644018f83450b4e931813c42031..0000000000000000000000000000000000000000 --- a/downloads/136.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8aaf0b419ec65da6023d756873a3a8ec20b1f5ecd466b732c12a99809e7d8df5 -size 1309173 diff --git a/downloads/137.jpg b/downloads/137.jpg deleted file mode 100644 index 04291caf6002fff7e51b065ea210b204dac29704..0000000000000000000000000000000000000000 Binary files a/downloads/137.jpg and /dev/null differ diff --git a/downloads/138.jpg b/downloads/138.jpg deleted file mode 100644 index 5fb1f9123eed06ffba62116768bc6f4dd7f10e6c..0000000000000000000000000000000000000000 Binary files a/downloads/138.jpg and /dev/null differ diff --git a/downloads/139.jpg b/downloads/139.jpg deleted file mode 100644 index 4d05633c26583c3da75ba7c87d87b65e4a69f656..0000000000000000000000000000000000000000 --- a/downloads/139.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a3b3be7cc5bd49d0257399f90282d0d379ea75841b51a2a1b493dbf3bc76e669 -size 1040559 diff --git a/downloads/14.png b/downloads/14.png deleted file mode 100644 index c65e4aba06ebee3c01fa1fddd397a9398b357933..0000000000000000000000000000000000000000 Binary files a/downloads/14.png and /dev/null differ diff --git a/downloads/140.jpg b/downloads/140.jpg deleted file mode 100644 index 56ab942007bd3a95d121db19731b83fc400034fb..0000000000000000000000000000000000000000 Binary files a/downloads/140.jpg and /dev/null differ diff --git a/downloads/141.jpg b/downloads/141.jpg deleted file mode 100644 index 01192eba307242452cadf5733b3465c9a2fdc2a1..0000000000000000000000000000000000000000 Binary files a/downloads/141.jpg and /dev/null differ diff --git a/downloads/142.jpg b/downloads/142.jpg deleted file mode 100644 index 565ea82f3e6fdcc67eb59ccfb852ec6abf41ee49..0000000000000000000000000000000000000000 Binary files a/downloads/142.jpg and /dev/null differ diff --git a/downloads/143.jpg b/downloads/143.jpg deleted file mode 100644 index d44341ee2b486e779746a89985e8c2101490ea41..0000000000000000000000000000000000000000 Binary files a/downloads/143.jpg and /dev/null differ diff --git a/downloads/144.jpg b/downloads/144.jpg deleted file mode 100644 index c5bd8bbdf54f04b525a5a6d8c6ac507953fcebaf..0000000000000000000000000000000000000000 Binary files a/downloads/144.jpg and /dev/null differ diff --git a/downloads/145.jpg b/downloads/145.jpg deleted file mode 100644 index 885f35418e5f303f864ed4e52c5cb3de3e4e20ef..0000000000000000000000000000000000000000 Binary files a/downloads/145.jpg and /dev/null differ diff --git a/downloads/146.jpg b/downloads/146.jpg deleted file mode 100644 index 5b2931c2cabf5c6a9955d6d1273ccbdbe43b23c6..0000000000000000000000000000000000000000 Binary files a/downloads/146.jpg and /dev/null differ diff --git a/downloads/147.jpg b/downloads/147.jpg deleted file mode 100644 index 51a92ebd138b2bab84dec8eb13a311def80c36d9..0000000000000000000000000000000000000000 Binary files a/downloads/147.jpg and /dev/null differ diff --git a/downloads/148.jpg b/downloads/148.jpg deleted file mode 100644 index 04506bb8be4ce924e3fc0acf34c88a759b2b741d..0000000000000000000000000000000000000000 Binary files a/downloads/148.jpg and /dev/null differ diff --git a/downloads/149.jpg b/downloads/149.jpg deleted file mode 100644 index a35d833d03f090fe02a4c10ffca93acce334545b..0000000000000000000000000000000000000000 Binary files a/downloads/149.jpg and /dev/null differ diff --git a/downloads/15.png b/downloads/15.png deleted file mode 100644 index c3781770d1dd6e4c97e4c199b74fa49403efa4e8..0000000000000000000000000000000000000000 Binary files a/downloads/15.png and /dev/null differ diff --git a/downloads/150.jpg b/downloads/150.jpg deleted file mode 100644 index 11ef04d5b0255eec6a93da45dc76163bbb6f9f20..0000000000000000000000000000000000000000 --- a/downloads/150.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:30e8b72e8546b156431982a3a3a8b287b7a5e1b4d0272a71592f6039b3d09dca -size 1252110 diff --git a/downloads/151.jpg b/downloads/151.jpg deleted file mode 100644 index 09bfc48f5b5a87b074ca592401b66ef761221746..0000000000000000000000000000000000000000 --- a/downloads/151.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1e9fdbe8fd001abd0f01e51c921d6ac4d1fd20370e3a04c882e6d06df39ea84c -size 1471889 diff --git a/downloads/152.jpg b/downloads/152.jpg deleted file mode 100644 index 7837704e301d898fca8530e5fc0ce51fb3c5338b..0000000000000000000000000000000000000000 Binary files a/downloads/152.jpg and /dev/null differ diff --git a/downloads/153.jpg b/downloads/153.jpg deleted file mode 100644 index 033c72e9829461701e21838750a5d4d2bb6f0ec7..0000000000000000000000000000000000000000 Binary files a/downloads/153.jpg and /dev/null differ diff --git a/downloads/154.jpg b/downloads/154.jpg deleted file mode 100644 index 424e59003b162ce63a096be56661f9fde049d09f..0000000000000000000000000000000000000000 Binary files a/downloads/154.jpg and /dev/null differ diff --git a/downloads/155.jpg b/downloads/155.jpg deleted file mode 100644 index b4284c8c77198d4aa327b8ef154514bb12827e5c..0000000000000000000000000000000000000000 Binary files a/downloads/155.jpg and /dev/null differ diff --git a/downloads/156.jpg b/downloads/156.jpg deleted file mode 100644 index ca8388cb35ff07f59726ef108c84b267c1323f9f..0000000000000000000000000000000000000000 Binary files a/downloads/156.jpg and /dev/null differ diff --git a/downloads/157.jpg b/downloads/157.jpg deleted file mode 100644 index 5d817bfb9b7858ea4cddb02da0671687aba81364..0000000000000000000000000000000000000000 --- a/downloads/157.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:125fac8dd4e1d70c3a8539ca3369a681be71f953e792964d7b06615b23f1c532 -size 1741734 diff --git a/downloads/158.jpg b/downloads/158.jpg deleted file mode 100644 index f85cea6e871e26ae5699d721c2cdd6912381c37f..0000000000000000000000000000000000000000 Binary files a/downloads/158.jpg and /dev/null differ diff --git a/downloads/159.jpg b/downloads/159.jpg deleted file mode 100644 index 9966c84e310b4e69ac5737ef6e815369d6f3579b..0000000000000000000000000000000000000000 Binary files a/downloads/159.jpg and /dev/null differ diff --git a/downloads/16.png b/downloads/16.png deleted file mode 100644 index 340c7f707f23fb870a9ac6ae77ae1ef5620e7f5c..0000000000000000000000000000000000000000 Binary files a/downloads/16.png and /dev/null differ diff --git a/downloads/160.jpg b/downloads/160.jpg deleted file mode 100644 index 3ef72a919f1b791c002637576484dc052596ce5d..0000000000000000000000000000000000000000 --- a/downloads/160.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d6a73d5a271a2b37f2e8c36a2bb2afc8cc65bf0199c345de16b25a185d4936a3 -size 1368360 diff --git a/downloads/161.jpg b/downloads/161.jpg deleted file mode 100644 index dfe13e460bef42ca10e1fe14c70bc84e55741b35..0000000000000000000000000000000000000000 Binary files a/downloads/161.jpg and /dev/null differ diff --git a/downloads/162.jpg b/downloads/162.jpg deleted file mode 100644 index 9deef6ba731787dcfb062143adddee1a370e0cf9..0000000000000000000000000000000000000000 Binary files a/downloads/162.jpg and /dev/null differ diff --git a/downloads/163.jpg b/downloads/163.jpg deleted file mode 100644 index 443a003923d46da9089b206101c70a8ced8a26c4..0000000000000000000000000000000000000000 Binary files a/downloads/163.jpg and /dev/null differ diff --git a/downloads/164.jpg b/downloads/164.jpg deleted file mode 100644 index ca566fa37ec95431b0106f6879e8567e2a6817bb..0000000000000000000000000000000000000000 Binary files a/downloads/164.jpg and /dev/null differ diff --git a/downloads/165.jpg b/downloads/165.jpg deleted file mode 100644 index e3cfc049aab2005cd2e357d02a38e15bdc2a978c..0000000000000000000000000000000000000000 Binary files a/downloads/165.jpg and /dev/null differ diff --git a/downloads/166.jpg b/downloads/166.jpg deleted file mode 100644 index 3ff337dd0e6b6d229f294c27095782792e61d91a..0000000000000000000000000000000000000000 --- a/downloads/166.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f2b1a73a2f367284e50c655af9b8b414163eebe44ed1a5ed63b367b525c0ca8b -size 2059972 diff --git a/downloads/167.jpg b/downloads/167.jpg deleted file mode 100644 index 057fb6ade65e8f30bdcd2e7821b162c33d85c8da..0000000000000000000000000000000000000000 Binary files a/downloads/167.jpg and /dev/null differ diff --git a/downloads/168.jpg b/downloads/168.jpg deleted file mode 100644 index 59897ffe8b0dd28023baf2b1dd25424621eb5530..0000000000000000000000000000000000000000 --- a/downloads/168.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2d08edaac81b9e91a63a9a62340320f8407b4f5a836bfd55ec43bdf253252cb3 -size 1776891 diff --git a/downloads/169.jpg b/downloads/169.jpg deleted file mode 100644 index fcc9e2094d13a17c1c27091c97e445f0ac70d1f1..0000000000000000000000000000000000000000 --- a/downloads/169.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ba97933866d682a497ede30e431d03b8ab8d9c1073f4ecbaeb7410539bca88e5 -size 1999830 diff --git a/downloads/17.png b/downloads/17.png deleted file mode 100644 index 656ffe848a59cba18a49f97d744f8dcceb56ea39..0000000000000000000000000000000000000000 Binary files a/downloads/17.png and /dev/null differ diff --git a/downloads/170.jpg b/downloads/170.jpg deleted file mode 100644 index ccc02be6ecac67fcc7e1578b2af37f4797d4775e..0000000000000000000000000000000000000000 Binary files a/downloads/170.jpg and /dev/null differ diff --git a/downloads/171.jpg b/downloads/171.jpg deleted file mode 100644 index 3b178562b7de0910d7f1e4d7ffccbcd9e048c0de..0000000000000000000000000000000000000000 Binary files a/downloads/171.jpg and /dev/null differ diff --git a/downloads/172.jpg b/downloads/172.jpg deleted file mode 100644 index c34ba6fb4bd2f542814510d343ca3aa52f5e560e..0000000000000000000000000000000000000000 Binary files a/downloads/172.jpg and /dev/null differ diff --git a/downloads/173.jpg b/downloads/173.jpg deleted file mode 100644 index 551c11a30b00aee572d57de1837371a517f01c65..0000000000000000000000000000000000000000 --- a/downloads/173.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f234666149ba26ed37f7989a27fd2b4b9792f1d0d5152a496a44ecd8f2de8a48 -size 1662126 diff --git a/downloads/174.jpg b/downloads/174.jpg deleted file mode 100644 index db72e10257fd28adc92b06318bdba908b243b451..0000000000000000000000000000000000000000 Binary files a/downloads/174.jpg and /dev/null differ diff --git a/downloads/175.jpg b/downloads/175.jpg deleted file mode 100644 index 7ff55130596afd2aecf983eea06a0f04ebe65ee4..0000000000000000000000000000000000000000 Binary files a/downloads/175.jpg and /dev/null differ diff --git a/downloads/176.jpg b/downloads/176.jpg deleted file mode 100644 index 100087df0068c0bf27f4fdd22d6233dd7c433471..0000000000000000000000000000000000000000 Binary files a/downloads/176.jpg and /dev/null differ diff --git a/downloads/177.jpg b/downloads/177.jpg deleted file mode 100644 index 8c522fcb08672b1ceee1e425ff1c57498e83b1c5..0000000000000000000000000000000000000000 --- a/downloads/177.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f2d29dd122b80d85dec5cfae49cc28ece8acef1f6a2313a4f89e6807ed8ff342 -size 1278629 diff --git a/downloads/178.jpg b/downloads/178.jpg deleted file mode 100644 index f58f8434ecaa3292df954be80c1fac7e053d00e7..0000000000000000000000000000000000000000 Binary files a/downloads/178.jpg and /dev/null differ diff --git a/downloads/179.jpg b/downloads/179.jpg deleted file mode 100644 index e65ed0ee9561678b3700d5b777ba025e74601b93..0000000000000000000000000000000000000000 Binary files a/downloads/179.jpg and /dev/null differ diff --git a/downloads/18.png b/downloads/18.png deleted file mode 100644 index 9e30793ba18d5ef09ef5b6dca5da5414df674576..0000000000000000000000000000000000000000 --- a/downloads/18.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d72153b9dc95642c90d989cdda7a38941ce27415f30f82b29aa2687ba32b5eed -size 1049695 diff --git a/downloads/180.jpg b/downloads/180.jpg deleted file mode 100644 index 40d849db3141075ccbdf10a402edbcb83b04453b..0000000000000000000000000000000000000000 Binary files a/downloads/180.jpg and /dev/null differ diff --git a/downloads/181.jpg b/downloads/181.jpg deleted file mode 100644 index b71fbe5472b7a4b65bbda7259dacba42a859f6b9..0000000000000000000000000000000000000000 Binary files a/downloads/181.jpg and /dev/null differ diff --git a/downloads/182.jpg b/downloads/182.jpg deleted file mode 100644 index 6e4fb9177fac1c58e788c5e7a1497586270674b6..0000000000000000000000000000000000000000 Binary files a/downloads/182.jpg and /dev/null differ diff --git a/downloads/183.jpg b/downloads/183.jpg deleted file mode 100644 index f41cb9ee780308c86d7e24326494fbec0b1c5747..0000000000000000000000000000000000000000 --- a/downloads/183.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09224a86e32697573e460bb11eadd7b986b7c0e36fc1d9d7122c8b9d0fe444d1 -size 1277662 diff --git a/downloads/184.jpg b/downloads/184.jpg deleted file mode 100644 index 24b5c8288983fbf5e82f35f1bd16914807b00d51..0000000000000000000000000000000000000000 Binary files a/downloads/184.jpg and /dev/null differ diff --git a/downloads/185.jpg b/downloads/185.jpg deleted file mode 100644 index ad8bb8994a6bdb591d918d78e0ce6df99f9499ad..0000000000000000000000000000000000000000 Binary files a/downloads/185.jpg and /dev/null differ diff --git a/downloads/186.jpg b/downloads/186.jpg deleted file mode 100644 index 9b948495db694a2a86179da5b27e3be7ce12ed68..0000000000000000000000000000000000000000 --- a/downloads/186.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:565dabb9b0ca25f3c6bdb33f12b16312818e9a8fef358617746e45fac8135ca5 -size 1031309 diff --git a/downloads/187.jpg b/downloads/187.jpg deleted file mode 100644 index 7c146ed9f2d1339bb4404f784504090ca4bffd90..0000000000000000000000000000000000000000 --- a/downloads/187.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ad7689fa02b9d294e7b79a0775fa631765f36e4a42c31526d37678e33f6932e -size 1844540 diff --git a/downloads/188.jpg b/downloads/188.jpg deleted file mode 100644 index 33aa1cc9ff6f5d68514baadd2ea769a857c351a5..0000000000000000000000000000000000000000 Binary files a/downloads/188.jpg and /dev/null differ diff --git a/downloads/189.jpg b/downloads/189.jpg deleted file mode 100644 index 6179e827df89ffb319ebf4a3d47c7d0c556a639c..0000000000000000000000000000000000000000 --- a/downloads/189.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a7b97a4ed30718dff2a78275ad8f0a281da72a2a6c0f764da41b7ef6b5582223 -size 1625615 diff --git a/frontend/urls.py b/frontend/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..6db6e22cf241b2a35edff4c7588610bd05de028e --- /dev/null +++ b/frontend/urls.py @@ -0,0 +1,18 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('', views.index, name='index'), + path('calendar/', views.index, name='calendar'), + path('bhajan/', views.index, name='bhajan'), + path('bhajan//', views.index, name='bhajan_detail'), + path('setting/', views.index, name='setting'), + path('books/', views.index, name='books'), + path('change-password/', views.index, name='change_password'), + path('notification/', views.index, name='notification'), + path('notification-setting/', views.index, name='notification_setting'), + path('profile/', views.index, name='profile'), + path('login/', views.index, name='login'), + path('logout/', views.index, name='logout'), + path('register/', views.index, name='register'), +] \ No newline at end of file diff --git a/frontend/views.py b/frontend/views.py new file mode 100644 index 0000000000000000000000000000000000000000..7f9f1011bb4e0995ecc4563c9d07eb77441522c5 --- /dev/null +++ b/frontend/views.py @@ -0,0 +1,4 @@ +from django.shortcuts import render + +def index(request, id=None): + return render(request, 'index.html') diff --git a/hsapssconnect/__pycache__/__init__.cpython-313.pyc b/hsapssconnect/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bccd3d606c0791c82e5503a998adb47c0542d09 Binary files /dev/null and b/hsapssconnect/__pycache__/__init__.cpython-313.pyc differ diff --git a/hsapssconnect/__pycache__/asgi.cpython-313.pyc b/hsapssconnect/__pycache__/asgi.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6c6e0534bda8f9696cb97854aecbc1858611d53 Binary files /dev/null and b/hsapssconnect/__pycache__/asgi.cpython-313.pyc differ diff --git a/hsapssconnect/__pycache__/settings.cpython-313.pyc b/hsapssconnect/__pycache__/settings.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6f2e94318e99e2a1ad224ff2fa798182792f197 Binary files /dev/null and b/hsapssconnect/__pycache__/settings.cpython-313.pyc differ diff --git a/hsapssconnect/__pycache__/urls.cpython-313.pyc b/hsapssconnect/__pycache__/urls.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c85ad5dfb5403ace406d83b2ded688e47e656c2 Binary files /dev/null and b/hsapssconnect/__pycache__/urls.cpython-313.pyc differ diff --git a/hsapssconnect/__pycache__/wsgi.cpython-313.pyc b/hsapssconnect/__pycache__/wsgi.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61cb92c064bacb3eccb28fd31b366acd0a8c9cd1 Binary files /dev/null and b/hsapssconnect/__pycache__/wsgi.cpython-313.pyc differ diff --git a/hsapssconnect/asgi.py b/hsapssconnect/asgi.py index b7fda2eab08e8b20576f3149448ba1bdfbe3efbb..c2a3aabad45f1c649c6d2ee4b138fff1bdc90a42 100644 --- a/hsapssconnect/asgi.py +++ b/hsapssconnect/asgi.py @@ -8,9 +8,18 @@ https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/ """ import os - +from channels.auth import AuthMiddlewareStack from django.core.asgi import get_asgi_application +from channels.routing import ProtocolTypeRouter, URLRouter +import notification.routing os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hsapssconnect.settings") -application = get_asgi_application() +application = ProtocolTypeRouter({ + 'http': get_asgi_application(), + 'websocket': AuthMiddlewareStack( + URLRouter( + notification.routing.websocket_urlpatterns + ) + ), +}) \ No newline at end of file diff --git a/hsapssconnect/settings.py b/hsapssconnect/settings.py index fb980ad83ffc6bd80fd0547789de4aa32a7319a9..0a54b71adb1e14d204e2db953db89c46d9acd3c1 100644 --- a/hsapssconnect/settings.py +++ b/hsapssconnect/settings.py @@ -26,11 +26,13 @@ SECRET_KEY = "django-insecure-lde0hgz*y9#h@sbz_u6&=&=i9cef23em^sax91iqb_)1#2s*qd # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = ["*", "127.0.0.1", "localhost","thejagstudio-connect.hf.space"] +ALLOWED_HOSTS = ["*", "127.0.0.1", "localhost", "thejagstudio-connect.hf.space", "zjkjjkxf-8000.use.devtunnels.ms"] CORS_ORIGIN_ALLOW_ALL = True -CORS_ALLOW_CREDENTIALS = False -CSRF_TRUSTED_ORIGINS = ["https://thejagstudio-connect.hf.space"] -# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') +CORS_ALLOW_CREDENTIALS = True +CORS_ALLOWED_ORIGINS = ["https://thejagstudio-connect.hf.space", "https://zjkjjkxf-8000.use.devtunnels.ms"] + +CSRF_TRUSTED_ORIGINS = ["https://thejagstudio-connect.hf.space", "https://zjkjjkxf-8000.use.devtunnels.ms"] +# SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") # SECURE_SSL_REDIRECT = True # SESSION_COOKIE_SECURE = True # CSRF_COOKIE_SECURE = True @@ -44,19 +46,21 @@ INSTALLED_APPS = [ "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", - "django.contrib.staticfiles", + "daphne", "api", + "notification", "corsheaders", "import_export", "rest_framework", "rest_framework_simplejwt", "rest_framework_simplejwt.token_blacklist", + "django.contrib.staticfiles", ] MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", - 'corsheaders.middleware.CorsMiddleware', + "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", @@ -69,7 +73,7 @@ ROOT_URLCONF = "hsapssconnect.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], + "DIRS": ["templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ @@ -83,19 +87,23 @@ TEMPLATES = [ ] WSGI_APPLICATION = "hsapssconnect.wsgi.application" - - +ASGI_APPLICATION = "hsapssconnect.asgi.application" +CHANNEL_LAYERS = { + "default": { + "BACKEND": "channels.layers.InMemoryChannelLayer", + } +} # Database # https://docs.djangoproject.com/en/5.0/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'postgres', - 'USER': 'postgres.psjobjezrtkjvenhsmge', - 'PORT': 6543, - 'PASSWORD': 'ErO9vgKcwCA1bdah', - 'HOST': 'aws-0-us-east-1.pooler.supabase.com', + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": "postgres", + "USER": "postgres.psjobjezrtkjvenhsmge", + "PORT": 6543, + "PASSWORD": "ErO9vgKcwCA1bdah", + "HOST": "aws-0-us-east-1.pooler.supabase.com", } # "default": { # "ENGINE": "django.db.backends.sqlite3", @@ -143,27 +151,27 @@ STATIC_URL = "static/" # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -AUTH_USER_MODEL = 'api.Bhagat' +AUTH_USER_MODEL = "api.Bhagat" -RECAPTCHA_SITE_KEY = '6LfDVWUqAAAAAOPlzTro2t51YeymYoz-Pt89tarF' -RECAPTCHA_SECRET_KEY = '6LfDVWUqAAAAACzIE4ZKx71R0smuDVJaV-GBLR66' +RECAPTCHA_SITE_KEY = "6LfDVWUqAAAAAOPlzTro2t51YeymYoz-Pt89tarF" +RECAPTCHA_SECRET_KEY = "6LfDVWUqAAAAACzIE4ZKx71R0smuDVJaV-GBLR66" REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'rest_framework_simplejwt.authentication.JWTAuthentication', - ), - 'DEFAULT_RENDERER_CLASSES': [ - 'rest_framework.renderers.JSONRenderer', - 'rest_framework.renderers.BrowsableAPIRenderer', + "DEFAULT_AUTHENTICATION_CLASSES": ("rest_framework_simplejwt.authentication.JWTAuthentication",), + "DEFAULT_RENDERER_CLASSES": [ + "rest_framework.renderers.JSONRenderer", + "rest_framework.renderers.BrowsableAPIRenderer", ], } SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60), - 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), - 'ROTATE_REFRESH_TOKENS': False, - 'ALGORITHM': 'HS256', - 'SIGNING_KEY': 'HariPremci6fhen4G3iGpCE0IYrhLOPCWAvoxxVw', - 'AUTH_HEADER_TYPES': ('Bearer',), + "ACCESS_TOKEN_LIFETIME": timedelta(days=60), + "REFRESH_TOKEN_LIFETIME": timedelta(days=120), + "ROTATE_REFRESH_TOKENS": False, + "ALGORITHM": "HS256", + "SIGNING_KEY": "HariPremci6fhen4G3iGpCE0IYrhLOPCWAvoxxVw", + "AUTH_HEADER_TYPES": ("Bearer",), } + +WEBPUSH_SETTINGS = {"VAPID_PUBLIC_KEY": "BOE7XX5MdzDx4thHOajMNZJj8C1LqGaa8X35O7hww5uzsvFyjFAcRZw71AUAYubeggvOoSvkB4nd1xtPkPFfB9U", "VAPID_PRIVATE_KEY": "gdd6ff_ti4W33uj23npZRIUZM6ViyTIOueHIv01Q7Lc", "VAPID_ADMIN_EMAIL": "thejagstudio@gmail.com"} diff --git a/hsapssconnect/urls.py b/hsapssconnect/urls.py index 39e78050c3b876926f61b8cac010d5b0afaf8232..894c3650ac99c095d24d91c5afdb8f9b8b63157e 100644 --- a/hsapssconnect/urls.py +++ b/hsapssconnect/urls.py @@ -5,4 +5,5 @@ from django.urls.conf import include urlpatterns = [ path("admin/", admin.site.urls), path("api/", include("api.urls")), + path("notifications/", include("notification.urls")) ] diff --git a/notification/__init__.py b/notification/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/notification/__pycache__/__init__.cpython-313.pyc b/notification/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3061c9a06381c2bea3cfc24b743faac920ad8187 Binary files /dev/null and b/notification/__pycache__/__init__.cpython-313.pyc differ diff --git a/notification/__pycache__/admin.cpython-313.pyc b/notification/__pycache__/admin.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3fe6b3dc0141849fc18417bd1a712a73de0bcfd8 Binary files /dev/null and b/notification/__pycache__/admin.cpython-313.pyc differ diff --git a/notification/__pycache__/apps.cpython-313.pyc b/notification/__pycache__/apps.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..587d8d90e8b5ead0dfc42707f8f786816b8b9e39 Binary files /dev/null and b/notification/__pycache__/apps.cpython-313.pyc differ diff --git a/notification/__pycache__/consumers.cpython-313.pyc b/notification/__pycache__/consumers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a57000ec87971c0b40e9ab3d2591ed90b260d56 Binary files /dev/null and b/notification/__pycache__/consumers.cpython-313.pyc differ diff --git a/notification/__pycache__/models.cpython-313.pyc b/notification/__pycache__/models.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d71f8083b25c41fc1f8c7032b011bd9165b67517 Binary files /dev/null and b/notification/__pycache__/models.cpython-313.pyc differ diff --git a/notification/__pycache__/routing.cpython-313.pyc b/notification/__pycache__/routing.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70be5b189dd565006aace1ca76b4dcf8945417e3 Binary files /dev/null and b/notification/__pycache__/routing.cpython-313.pyc differ diff --git a/notification/__pycache__/urls.cpython-313.pyc b/notification/__pycache__/urls.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd23e7febb3b2e7b0570319277399df8ade2ab00 Binary files /dev/null and b/notification/__pycache__/urls.cpython-313.pyc differ diff --git a/notification/__pycache__/views.cpython-313.pyc b/notification/__pycache__/views.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78972135feeb00a029cacf69d44a8035c4202032 Binary files /dev/null and b/notification/__pycache__/views.cpython-313.pyc differ diff --git a/notification/admin.py b/notification/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e --- /dev/null +++ b/notification/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/notification/apps.py b/notification/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..8757bbe51e206971108c1724396158b4420f1c62 --- /dev/null +++ b/notification/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class NotificationConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'notification' diff --git a/notification/consumers.py b/notification/consumers.py new file mode 100644 index 0000000000000000000000000000000000000000..d95e19bb9c8da1ad5b69f38d102e392d8a7bd3ec --- /dev/null +++ b/notification/consumers.py @@ -0,0 +1,33 @@ +import json +from channels.generic.websocket import AsyncWebsocketConsumer + +class NotificationConsumer(AsyncWebsocketConsumer): + + async def connect(self): + self.group_name = 'Yuvak' + await self.channel_layer.group_add( + self.group_name, + self.channel_name + ) + await self.accept() + + async def disconnect(self, close_code): + await self.channel_layer.group_discard( + self.group_name, + self.channel_name + ) + + async def receive(self, text_data): + data = json.loads(text_data) + message = data['data'] + await self.channel_layer.group_send( + self.group_name, + { + 'type': 'send_notification', + 'message': message + } + ) + + async def send_notification(self, event): + message = event['message'] + await self.send(text_data=json.dumps({'message': message})) \ No newline at end of file diff --git a/notification/migrations/__init__.py b/notification/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/notification/migrations/__pycache__/__init__.cpython-313.pyc b/notification/migrations/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee2e3d14e678dc17c4c1bbf7fdecee5757e3c31a Binary files /dev/null and b/notification/migrations/__pycache__/__init__.cpython-313.pyc differ diff --git a/notification/models.py b/notification/models.py new file mode 100644 index 0000000000000000000000000000000000000000..71a836239075aa6e6e4ecb700e9c42c95c022d91 --- /dev/null +++ b/notification/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/notification/routing.py b/notification/routing.py new file mode 100644 index 0000000000000000000000000000000000000000..3c0574bfaab6bd70de956a3ee122f8ef12aa18bc --- /dev/null +++ b/notification/routing.py @@ -0,0 +1,6 @@ +from django.urls import re_path +from . import consumers + +websocket_urlpatterns = [ + re_path(r'ws/notification/$', consumers.NotificationConsumer.as_asgi()), +] \ No newline at end of file diff --git a/notification/tests.py b/notification/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6 --- /dev/null +++ b/notification/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/notification/urls.py b/notification/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..b98ce8f6b2151892b664ed491379aae9f4a95c22 --- /dev/null +++ b/notification/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from . import views + +urlpatterns = [ + # path('notifications/', views.notification_list, name='notification_list'), + # path('notifications//', views.notification_detail, name='notification_detail'), +] \ No newline at end of file diff --git a/notification/views.py b/notification/views.py new file mode 100644 index 0000000000000000000000000000000000000000..91ea44a218fbd2f408430959283f0419c921093e --- /dev/null +++ b/notification/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/requirements.txt b/requirements.txt index 39313b9899e7d76d216645ee2a7a45ed693305f3..d61e00fb92e68009b77283942f56b13ee0cf67c8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,51 +1,10 @@ -asgiref==3.8.1 -blinker==1.8.2 -certifi==2024.8.30 -charset-normalizer==3.3.2 -click==8.1.7 -colorama==0.4.6 -diff-match-patch==20230430 -Django==4.2.16 -django-admin==2.0.2 -django-cors-headers==4.4.0 -django-excel-response2==3.0.6 -django-import-export==4.1.1 -django-six==1.0.5 -djangorestframework==3.15.2 -djangorestframework-simplejwt==5.3.1 -excel-base==1.0.4 -filelock==3.16.1 -fsspec==2024.9.0 -google-recaptcha==2.0.1 -idna==3.10 -importlib_metadata==8.5.0 -isoweek==1.3.3 -itsdangerous==2.2.0 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -mpmath==1.3.0 -networkx==3.2.1 -numpy==2.0.2 -packaging==24.1 -pillow==10.4.0 -psutil==6.0.0 -psycopg2==2.9.10 -PyJWT==2.9.0 -python-dateutil==2.9.0.post0 -PyYAML==6.0.2 -regex==2024.9.11 -requests==2.32.3 -screen==1.0.1 -six==1.16.0 -sqlparse==0.5.1 -sympy==1.13.3 -tablib==3.5.0 -TimeConvert==3.0.13 -tqdm==4.66.5 -typing_extensions==4.12.2 -tzdata==2024.1 -tzlocal==5.2 -urllib3==2.2.3 -Werkzeug==3.0.4 -xlwt==1.3.0 -zipp==3.20.2 +django +django-cors-headers +djangorestframework +djangorestframework-simplejwt +psycopg2 +django-import-export +requests +channels[daphne] +channels-redis +pywebpush \ No newline at end of file