├── config ├── __init__.py ├── tests.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── apps.py ├── admin.py ├── urls.py ├── models.py ├── serializers.py └── views.py ├── mess ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── tests.py ├── apps.py ├── admin.py ├── urls.py ├── models.py ├── serializers.py └── views.py ├── team ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0002_auto_20200211_0931.py │ ├── 0003_auto_20200211_1014.py │ ├── 0004_teammember_role.py │ ├── 0006_teammember_role.py │ ├── 0001_initial.py │ ├── 0005_auto_20200405_1247.py │ └── 0007_auto_20200405_1256.py ├── tests.py ├── apps.py ├── urls.py ├── admin.py ├── views.py ├── serializers.py └── models.py ├── academics ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_added_academic_section.py ├── tests.py ├── apps.py ├── admin.py ├── urls.py ├── serializers.py ├── models.py └── views.py ├── grievance ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── tests.py ├── admin.py ├── apps.py ├── forms.py ├── urls.py ├── models.py ├── views.py └── serializers.py ├── noticeboard ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── tests.py ├── apps.py ├── admin.py ├── urls.py ├── models.py ├── permissions.py ├── serializers.py └── views.py ├── workshop ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0017_auto_20200503_0645.py │ ├── 0018_auto_20200503_0712.py │ ├── 0028_auto_20201127_1401.py │ ├── 0026_workshop_is_workshop.py │ ├── 0025_auto_20201121_1747.py │ ├── 0007_auto_20191010_0706.py │ ├── 0027_auto_20201126_1447.py │ ├── 0006_auto_20191010_0702.py │ ├── 0019_auto_20200503_1844.py │ ├── 0014_auto_20200407_0831.py │ ├── 0023_auto_20201120_1353.py │ ├── 0029_auto_20201206_1541.py │ ├── 0024_auto_20201121_1243.py │ ├── 0005_auto_20191010_0702.py │ ├── 0030_auto_20201222_2359.py │ ├── 0016_auto_20200503_0426.py │ ├── 0010_auto_20200211_0929.py │ ├── 0001_initial.py │ ├── 0013_auto_20200303_2200.py │ ├── 0020_auto_20200503_1950.py │ ├── 0002_auto_20191010_0507.py │ ├── 0004_auto_20191010_0656.py │ ├── 0031_auto_20201223_0935.py │ ├── 0009_auto_20191021_1413.py │ ├── 0011_auto_20200211_1226.py │ ├── 0003_auto_20191010_0519.py │ ├── 0008_auto_20191010_1030.py │ ├── 0012_auto_20200303_2155.py │ ├── 0015_auto_20200503_0331.py │ ├── 0022_auto_20201120_1230.py │ └── 0021_entity_event_eventresource.py ├── tests.py ├── apps.py ├── urls.py ├── admin.py ├── permissions.py └── models.py ├── workshops ├── __init__.py ├── wsgi.py ├── urls.py └── settings.py ├── authentication ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0007_remove_userprofile_is_admin.py │ ├── 0009_remove_userprofile_is_admin.py │ ├── 0002_auto_20191009_0329.py │ ├── 0006_userprofile_is_admin.py │ ├── 0008_userprofile_is_admin.py │ ├── 0011_userprofile_photo_url.py │ ├── 0013_userprofile_can_post_notice.py │ ├── 0012_auto_20200303_2140.py │ ├── 0010_userprofile_phone_number.py │ ├── 0014_userprofile_can_add_parliament_details.py │ ├── 0005_auto_20191009_1206.py │ ├── 0004_auto_20191009_1201.py │ ├── 0003_auto_20191009_1118.py │ └── 0001_initial.py ├── tests.py ├── apps.py ├── urls.py ├── admin.py ├── models.py ├── views.py ├── utils.py └── serializers.py ├── lost_and_found ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0002_auto_20220215_1655.py │ └── 0001_initial.py ├── tests.py ├── admin.py ├── apps.py ├── urls.py ├── models.py ├── serializers.py └── views.py ├── parliament_detail ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── tests.py ├── apps.py ├── admin.py ├── permissions.py ├── urls.py ├── models.py ├── serializers.py └── views.py ├── README.md ├── Procfile ├── service_account.json.aes ├── .editorconfig ├── requirements.txt ├── app.json ├── Pipfile ├── manage.py ├── .github └── workflows │ └── lint.yml ├── keys.json └── .gitignore /config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/tests.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mess/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /team/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /academics/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /grievance/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /noticeboard/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /workshop/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /workshops/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /authentication/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lost_and_found/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mess/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /team/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /academics/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /grievance/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /parliament_detail/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /workshop/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## IIT BHU Workshops App 2 | -------------------------------------------------------------------------------- /authentication/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lost_and_found/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /noticeboard/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /parliament_detail/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /academics/tests.py: -------------------------------------------------------------------------------- 1 | # Create your tests here. 2 | -------------------------------------------------------------------------------- /noticeboard/tests.py: -------------------------------------------------------------------------------- 1 | # Create your tests here. 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | release: python manage.py migrate 2 | web: gunicorn workshops.wsgi -------------------------------------------------------------------------------- /mess/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /grievance/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /team/tests.py: -------------------------------------------------------------------------------- 1 | # from django.test import TestCase 2 | 3 | # # Create your tests here. 4 | -------------------------------------------------------------------------------- /workshop/tests.py: -------------------------------------------------------------------------------- 1 | # from django.test import TestCase 2 | 3 | # # Create your tests here. 4 | -------------------------------------------------------------------------------- /lost_and_found/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /parliament_detail/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /authentication/tests.py: -------------------------------------------------------------------------------- 1 | # from django.test import TestCase 2 | 3 | # # Create your tests here. 4 | -------------------------------------------------------------------------------- /mess/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MessConfig(AppConfig): 5 | name = 'mess' 6 | -------------------------------------------------------------------------------- /service_account.json.aes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IIT-BHU-InstiApp/lite-hai-backend/HEAD/service_account.json.aes -------------------------------------------------------------------------------- /team/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TeamConfig(AppConfig): 5 | name = 'team' 6 | -------------------------------------------------------------------------------- /config/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ConfigConfig(AppConfig): 5 | name = 'config' 6 | -------------------------------------------------------------------------------- /config/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import ConfigVar 3 | 4 | admin.site.register(ConfigVar) 5 | -------------------------------------------------------------------------------- /workshop/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WorkshopConfig(AppConfig): 5 | name = 'workshop' 6 | -------------------------------------------------------------------------------- /academics/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AcademicsConfig(AppConfig): 5 | name = 'academics' 6 | -------------------------------------------------------------------------------- /grievance/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . models import Complaint 3 | 4 | admin.site.register(Complaint) 5 | -------------------------------------------------------------------------------- /grievance/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class GrievanceConfig(AppConfig): 5 | name = 'grievance' 6 | -------------------------------------------------------------------------------- /noticeboard/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NoticeboardConfig(AppConfig): 5 | name = "noticeboard" 6 | -------------------------------------------------------------------------------- /lost_and_found/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import LostAndFound 3 | 4 | admin.site.register(LostAndFound) 5 | -------------------------------------------------------------------------------- /lost_and_found/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class LostAndFoundConfig(AppConfig): 5 | name = 'lost_and_found' 6 | -------------------------------------------------------------------------------- /authentication/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AuthenticationConfig(AppConfig): 5 | name = 'authentication' 6 | -------------------------------------------------------------------------------- /parliament_detail/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ParliamentDetailConfig(AppConfig): 5 | name = 'parliament_detail' 6 | -------------------------------------------------------------------------------- /team/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import TeamView 3 | 4 | urlpatterns = [ 5 | path('team/', TeamView.as_view(), name='team') 6 | ] 7 | -------------------------------------------------------------------------------- /noticeboard/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import NoticeBoard 3 | 4 | # Register your models here. 5 | admin.site.register(NoticeBoard) 6 | -------------------------------------------------------------------------------- /config/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import ConfigView 3 | 4 | urlpatterns = [ 5 | path('config/', ConfigView.as_view(), name='config'), 6 | ] 7 | -------------------------------------------------------------------------------- /mess/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . models import Mess, Hostel, Bill 3 | 4 | admin.site.register(Mess) 5 | admin.site.register(Hostel) 6 | admin.site.register(Bill) 7 | -------------------------------------------------------------------------------- /grievance/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import Complaint 3 | 4 | class ComplaintForm(forms.ModelForm): 5 | class Meta: 6 | model = Complaint 7 | fields = '__all__' 8 | -------------------------------------------------------------------------------- /config/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class ConfigVar(models.Model): 4 | name = models.CharField(max_length=255) 5 | value = models.TextField() 6 | 7 | def __str__(self): 8 | return f'{self.name}' 9 | -------------------------------------------------------------------------------- /academics/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import AcademicSchedule, ProfsAndHODs, StudyMaterials 3 | 4 | admin.site.register(AcademicSchedule) 5 | admin.site.register(ProfsAndHODs) 6 | admin.site.register(StudyMaterials) 7 | -------------------------------------------------------------------------------- /config/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import ConfigVar 3 | 4 | class ConfigVarSerializer(serializers.ModelSerializer): 5 | class Meta: 6 | model = ConfigVar 7 | fields = ('name', 'value') 8 | -------------------------------------------------------------------------------- /parliament_detail/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import * 3 | 4 | # Register your models here. 5 | admin.site.register(Contact) 6 | admin.site.register(Update) 7 | admin.site.register(Suggestion) 8 | admin.site.register(Committee) 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org/ 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | charset = utf-8 12 | 13 | [*.py] 14 | max_line_length = 100 15 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==2.2.10 2 | django-cors-headers==3.1.1 3 | django-heroku==0.3.1 4 | djangorestframework==3.10.3 5 | drf-yasg2==1.19.1 6 | firebase-admin==3.0.0 7 | gunicorn==19.9.0 8 | pyAesCrypt==0.4.3 9 | pylint-django==2.0.13 10 | python-decouple==3.1 11 | psycopg2==2.8.6 12 | -------------------------------------------------------------------------------- /authentication/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import LoginView, ProfileView, ProfileSearchView 3 | 4 | urlpatterns = [ 5 | path("login/", LoginView.as_view(), name="login"), 6 | path("profile/", ProfileView.as_view(), name="profile"), 7 | path("profile/search/", ProfileSearchView.as_view(), name="profile-search"), 8 | ] 9 | -------------------------------------------------------------------------------- /lost_and_found/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import ( 3 | CreateLostAndFoundView, LostAndFoundListView) 4 | 5 | urlpatterns = [ 6 | path('lostandfound/create/', CreateLostAndFoundView.as_view(), 7 | name='create_grievance'), 8 | path('lostandfound/list/', 9 | LostAndFoundListView.as_view(), name='list_lost_and_found'), 10 | ] 11 | -------------------------------------------------------------------------------- /authentication/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import UserProfile 3 | 4 | 5 | @admin.register(UserProfile) 6 | class UserProfileAdmin(admin.ModelAdmin): 7 | readonly_fields = ('photo_url',) 8 | list_display = ('__str__', 'uid', 'email', 'phone_number',) 9 | search_fields = ('uid', 'email', 'name',) 10 | list_filter = ('department', 'year_of_joining',) 11 | raw_id_fields = ('user',) 12 | -------------------------------------------------------------------------------- /team/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Role, TeamMember 3 | 4 | admin.site.register(Role) 5 | 6 | @admin.register(TeamMember) 7 | class TeamAdmin(admin.ModelAdmin): 8 | readonly_fields = ('github_image_url',) 9 | list_display = ('__str__', 'role', 'github_username') 10 | list_filter = ('role',) 11 | 12 | def get_queryset(self, request): 13 | return super().get_queryset(request).select_related('role') 14 | -------------------------------------------------------------------------------- /academics/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import(AcademicScheduleView, ProfsAndHODsView, StudyMaterialsView) 3 | 4 | urlpatterns = [path('academics/academic-schedule///', 5 | AcademicScheduleView.as_view()), 6 | path('academics/study-materials//', 7 | StudyMaterialsView.as_view()), 8 | path('academics/profs//', ProfsAndHODsView.as_view()), ] 9 | -------------------------------------------------------------------------------- /authentication/migrations/0007_remove_userprofile_is_admin.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-22 20:01 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0006_userprofile_is_admin'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='userprofile', 15 | name='is_admin', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /authentication/migrations/0009_remove_userprofile_is_admin.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-11 09:29 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0008_userprofile_is_admin'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='userprofile', 15 | name='is_admin', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /grievance/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import ( 3 | CreateGrievanceView, CountGrievanceView, GrievanceDetailView) 4 | 5 | urlpatterns = [ 6 | path('grievance/create/', CreateGrievanceView.as_view(), 7 | name='create_grievance'), 8 | path('grievance/count/', CountGrievanceView.as_view(), name='count_grievance'), 9 | path('grievance/details/', 10 | GrievanceDetailView.as_view(), name='detail_grievance'), 11 | ] 12 | -------------------------------------------------------------------------------- /workshops/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for workshops project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'workshops.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /config/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics 2 | from rest_framework import permissions 3 | from .serializers import ConfigVarSerializer 4 | from .models import ConfigVar 5 | 6 | class ConfigView(generics.ListAPIView): 7 | """ 8 | Returns the list of all the config vars. 9 | """ 10 | permission_classes = (permissions.AllowAny,) 11 | serializer_class = ConfigVarSerializer 12 | # pylint: disable=no-member 13 | queryset = ConfigVar.objects.all() 14 | -------------------------------------------------------------------------------- /workshop/migrations/0017_auto_20200503_0645.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-05-03 06:45 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0016_auto_20200503_0426'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='tag', 15 | old_name='name', 16 | new_name='tag_name', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /workshop/migrations/0018_auto_20200503_0712.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-05-03 07:12 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0017_auto_20200503_0645'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='workshop', 15 | old_name='tag', 16 | new_name='tags', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /workshop/migrations/0028_auto_20201127_1401.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-11-27 08:31 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0027_auto_20201126_1447'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='entity', 15 | old_name='is_active', 16 | new_name='is_highlighted', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /mess/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import ( 3 | HostelListView, MessListView, 4 | MessDetailView, MessBillView 5 | ) 6 | 7 | urlpatterns = [ 8 | path('hostel/', HostelListView.as_view(), name='hostel-list'), 9 | path('hostel//', MessListView.as_view(), name='mess-list'), 10 | path('mess//', MessDetailView.as_view(), name='mess-detail'), 11 | path('mess//bill//', 12 | MessBillView.as_view(), name='bill-detail'), 13 | ] 14 | -------------------------------------------------------------------------------- /team/migrations/0002_auto_20200211_0931.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-11 09:31 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('team', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='teammember', 15 | name='github_image_url', 16 | field=models.URLField(blank=True, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /authentication/migrations/0002_auto_20191009_0329.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-09 03:29 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='userprofile', 15 | name='course', 16 | field=models.CharField(max_length=32), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /workshop/migrations/0026_workshop_is_workshop.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-11-22 05:21 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0025_auto_20201121_1747'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='workshop', 15 | name='is_workshop', 16 | field=models.BooleanField(default=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "addons": [ 3 | "heroku-postgresql" 4 | ], 5 | "buildpacks": [ 6 | { 7 | "url": "heroku/python" 8 | } 9 | ], 10 | "env": { 11 | "SERVICE_ACCOUNT_DECRYPT_KEY": { 12 | "required": true 13 | }, 14 | "SERVICE_ACCOUNT_ENC_SIZE": { 15 | "required": true 16 | } 17 | }, 18 | "formation": { 19 | "web": { 20 | "quantity": 1 21 | } 22 | }, 23 | "name": "workshops-app-backend", 24 | "scripts": { 25 | }, 26 | "stack": "heroku-18" 27 | } 28 | -------------------------------------------------------------------------------- /authentication/migrations/0006_userprofile_is_admin.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 07:43 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0005_auto_20191009_1206'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofile', 15 | name='is_admin', 16 | field=models.BooleanField(default=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /team/migrations/0003_auto_20200211_1014.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-11 10:14 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('team', '0002_auto_20200211_0931'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='teammember', 15 | name='github_image_url', 16 | field=models.URLField(blank=True, editable=False, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /authentication/migrations/0008_userprofile_is_admin.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-10 09:28 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0007_remove_userprofile_is_admin'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofile', 15 | name='is_admin', 16 | field=models.BooleanField(default=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /authentication/migrations/0011_userprofile_photo_url.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-11 21:32 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0010_userprofile_phone_number'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofile', 15 | name='photo_url', 16 | field=models.URLField(blank=True, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /authentication/migrations/0013_userprofile_can_post_notice.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2021-12-16 06:51 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0012_auto_20200303_2140'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofile', 15 | name='can_post_notice', 16 | field=models.BooleanField(default=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /team/migrations/0004_teammember_role.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-04-02 03:24 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('team', '0003_auto_20200211_1014'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='teammember', 15 | name='role', 16 | field=models.CharField(default='', max_length=100), 17 | preserve_default=False, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | autopep8="*" 8 | 9 | [packages] 10 | django = "==2.2.13" 11 | django-cors-headers = "*" 12 | django-heroku = "*" 13 | gunicorn = "*" 14 | djangorestframework = "*" 15 | firebase-admin = "*" 16 | pyaescrypt = "*" 17 | python-decouple = "*" 18 | pylint-django = "*" 19 | drf-yasg2 = "*" 20 | google-api-python-client = "*" 21 | google-auth-httplib2 = "*" 22 | google-auth-oauthlib = "*" 23 | 24 | [requires] 25 | python_version = "3.8" 26 | -------------------------------------------------------------------------------- /authentication/migrations/0012_auto_20200303_2140.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-03-03 21:40 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0011_userprofile_photo_url'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='userprofile', 15 | name='photo_url', 16 | field=models.URLField(blank=True, editable=False, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /authentication/migrations/0010_userprofile_phone_number.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-11 20:48 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0009_remove_userprofile_is_admin'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofile', 15 | name='phone_number', 16 | field=models.CharField(blank=True, max_length=15, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /authentication/migrations/0014_userprofile_can_add_parliament_details.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2022-01-08 10:20 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0013_userprofile_can_post_notice'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofile', 15 | name='can_add_parliament_details', 16 | field=models.BooleanField(default=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /noticeboard/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import ( 3 | NoticeListView, 4 | NoticeDetailView, 5 | NoticeUpvoteView, 6 | NoticeCreateView, 7 | NoticeDownvoteView, 8 | ) 9 | 10 | urlpatterns = [ 11 | path("noticeboard/", NoticeListView.as_view()), 12 | path("noticeboard/create/", NoticeCreateView.as_view()), 13 | path("noticeboard//", NoticeDetailView.as_view()), 14 | path("noticeboard//upvote/", NoticeUpvoteView.as_view()), 15 | path("noticeboard//downvote/", NoticeDownvoteView.as_view()), 16 | ] 17 | -------------------------------------------------------------------------------- /workshop/migrations/0025_auto_20201121_1747.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-11-21 12:17 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0024_auto_20201121_1243'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='club', 15 | name='subscribed_users', 16 | field=models.ManyToManyField(blank=True, related_name='club_subscriptions', to='authentication.UserProfile'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /team/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics 2 | from rest_framework import permissions 3 | # from rest_framework import status 4 | # from rest_framework.response import Response 5 | from .serializers import RoleSerializer 6 | from .models import Role 7 | 8 | class TeamView(generics.ListAPIView): 9 | """ 10 | Returns the list of all the people who have contributed to the making of this application. 11 | """ 12 | permission_classes = (permissions.AllowAny,) 13 | serializer_class = RoleSerializer 14 | # pylint: disable=no-member 15 | queryset = Role.objects.all() 16 | -------------------------------------------------------------------------------- /team/migrations/0006_teammember_role.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-04-05 12:49 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('team', '0005_auto_20200405_1247'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='teammember', 16 | name='role', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='team.Role'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /authentication/migrations/0005_auto_20191009_1206.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-09 12:06 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('authentication', '0004_auto_20191009_1201'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='userprofile', 17 | name='user', 18 | field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /config/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2021-01-16 12:05 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='ConfigVar', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('name', models.CharField(max_length=255)), 19 | ('value', models.TextField()), 20 | ], 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /noticeboard/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from authentication.models import UserProfile 3 | 4 | class NoticeBoard(models.Model): 5 | title = models.CharField(max_length=50) 6 | description = models.TextField(null=True, blank=True) 7 | date = models.DateTimeField() 8 | upvotes = models.IntegerField(default=0) 9 | downvotes = models.IntegerField(default=0) 10 | voters = models.ManyToManyField(UserProfile, blank=True) 11 | importance = models.IntegerField(default = 0) 12 | 13 | def __str__(self): 14 | # pylint: disable=no-member 15 | return self.title + " - " + str(self.date.strftime("%Y-%m-%d %H:%M:%S")) 16 | -------------------------------------------------------------------------------- /authentication/migrations/0004_auto_20191009_1201.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-09 12:01 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('authentication', '0003_auto_20191009_1118'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='userprofile', 17 | name='user', 18 | field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /workshop/migrations/0007_auto_20191010_0706.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 07:06 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0006_auto_20191010_0702'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='workshop', 15 | name='date', 16 | field=models.DateField(blank=True, null=True), 17 | ), 18 | migrations.AlterField( 19 | model_name='workshop', 20 | name='time', 21 | field=models.TimeField(blank=True, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /workshop/migrations/0027_auto_20201126_1447.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-11-26 09:17 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0026_workshop_is_workshop'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='entity', 15 | name='is_active', 16 | field=models.BooleanField(default=False), 17 | ), 18 | migrations.AddField( 19 | model_name='entity', 20 | name='is_permanent', 21 | field=models.BooleanField(default=False), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /workshop/migrations/0006_auto_20191010_0702.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 07:02 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0005_auto_20191010_0702'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='workshop', 15 | name='audience', 16 | field=models.CharField(blank=True, max_length=50), 17 | ), 18 | migrations.AlterField( 19 | model_name='workshop', 20 | name='location', 21 | field=models.CharField(blank=True, max_length=50), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'workshops.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint Checks 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | lint: 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: [ubuntu-18.04] 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions/setup-python@v2 19 | with: 20 | python-version: 3.8 21 | - name: Install dependencies with pipenv 22 | run: | 23 | pip install pipenv 24 | pipenv install 25 | - name: Run lint checks 26 | run: pipenv run pylint --load-plugins pylint_django team workshops workshop authentication config noticeboard academics 27 | -------------------------------------------------------------------------------- /academics/serializers.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=too-few-public-methods 2 | from rest_framework import serializers 3 | from .models import AcademicSchedule, ProfsAndHODs, StudyMaterials 4 | 5 | 6 | class AcademicScheduleSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = AcademicSchedule 9 | fields = ('department', 'year_of_joining', 'schedule_url',) 10 | 11 | 12 | class StudyMaterialsSerializer(serializers.ModelSerializer): 13 | class Meta: 14 | model = StudyMaterials 15 | fields = ('resource_url',) 16 | 17 | 18 | class ProfsAndHODsSerializer(serializers.ModelSerializer): 19 | class Meta: 20 | model = ProfsAndHODs 21 | fields = ('department', 'profs_and_HODs') 22 | -------------------------------------------------------------------------------- /team/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-11 09:29 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='TeamMember', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('name', models.CharField(max_length=100)), 19 | ('github_username', models.CharField(max_length=50)), 20 | ('github_image_url', models.URLField(null=True)), 21 | ], 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /team/migrations/0005_auto_20200405_1247.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-04-05 12:47 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('team', '0004_teammember_role'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='Role', 15 | fields=[ 16 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('name', models.CharField(max_length=100)), 18 | ], 19 | ), 20 | migrations.RemoveField( 21 | model_name='teammember', 22 | name='role', 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /workshop/migrations/0019_auto_20200503_1844.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-05-03 18:44 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0018_auto_20200503_0712'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='workshop', 15 | name='latitude', 16 | field=models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='workshop', 20 | name='longitude', 21 | field=models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /workshop/migrations/0014_auto_20200407_0831.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-04-07 08:31 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0012_auto_20200303_2140'), 10 | ('workshop', '0013_auto_20200303_2200'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RemoveField( 15 | model_name='workshop', 16 | name='attendees', 17 | ), 18 | migrations.AddField( 19 | model_name='workshop', 20 | name='interested_users', 21 | field=models.ManyToManyField(blank=True, related_name='interested_workshops', to='authentication.UserProfile'), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /team/migrations/0007_auto_20200405_1256.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-04-05 12:56 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('team', '0006_teammember_role'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RenameField( 15 | model_name='role', 16 | old_name='name', 17 | new_name='role', 18 | ), 19 | migrations.AlterField( 20 | model_name='teammember', 21 | name='role', 22 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='team_members', to='team.Role'), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /team/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from drf_yasg2.utils import swagger_serializer_method 3 | from .models import TeamMember, Role 4 | 5 | class TeamMemberSerializer(serializers.ModelSerializer): 6 | class Meta: 7 | model = TeamMember 8 | fields = ('name', 'github_username', 'github_image_url') 9 | 10 | 11 | class RoleSerializer(serializers.ModelSerializer): 12 | team_members = serializers.SerializerMethodField() 13 | 14 | @swagger_serializer_method(serializer_or_field=TeamMemberSerializer(many=True)) 15 | def get_team_members(self, obj): 16 | """ 17 | Team members for a particular role 18 | """ 19 | serializer = TeamMemberSerializer(obj.team_members, many=True) 20 | return serializer.data 21 | 22 | class Meta: 23 | model = Role 24 | fields = ('role', 'team_members') 25 | -------------------------------------------------------------------------------- /workshop/migrations/0023_auto_20201120_1353.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-11-20 08:23 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('workshop', '0022_auto_20201120_1230'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RemoveField( 15 | model_name='workshopresource', 16 | name='event', 17 | ), 18 | migrations.AlterField( 19 | model_name='workshopresource', 20 | name='workshop', 21 | field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='resources', to='workshop.Workshop'), 22 | preserve_default=False, 23 | ), 24 | migrations.DeleteModel( 25 | name='Event', 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /workshop/migrations/0029_auto_20201206_1541.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-12-06 10:11 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0028_auto_20201127_1401'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='workshop', 15 | name='audience', 16 | field=models.CharField(blank=True, max_length=100), 17 | ), 18 | migrations.AlterField( 19 | model_name='workshop', 20 | name='location', 21 | field=models.CharField(blank=True, max_length=100), 22 | ), 23 | migrations.AlterField( 24 | model_name='workshopresource', 25 | name='name', 26 | field=models.CharField(max_length=100), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /workshop/migrations/0024_auto_20201121_1243.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-11-21 07:13 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0012_auto_20200303_2140'), 10 | ('workshop', '0023_auto_20201120_1353'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RemoveField( 15 | model_name='entity', 16 | name='joint_secy', 17 | ), 18 | migrations.RemoveField( 19 | model_name='entity', 20 | name='secy', 21 | ), 22 | migrations.AddField( 23 | model_name='entity', 24 | name='point_of_contact', 25 | field=models.ManyToManyField(blank=True, related_name='entity_point_of_contact', to='authentication.UserProfile', verbose_name='Point of Contact'), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /workshop/migrations/0005_auto_20191010_0702.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 07:02 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0004_auto_20191010_0656'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='workshop', 15 | name='start_time', 16 | ), 17 | migrations.AddField( 18 | model_name='workshop', 19 | name='audience', 20 | field=models.CharField(default='', max_length=50), 21 | preserve_default=False, 22 | ), 23 | migrations.AddField( 24 | model_name='workshop', 25 | name='date', 26 | field=models.DateField(null=True), 27 | ), 28 | migrations.AddField( 29 | model_name='workshop', 30 | name='time', 31 | field=models.TimeField(null=True), 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /workshop/migrations/0030_auto_20201222_2359.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2020-12-22 18:29 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0029_auto_20201206_1541'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddIndex( 14 | model_name='tag', 15 | index=models.Index(fields=['tag_name', 'club'], name='workshop_ta_tag_nam_238116_idx'), 16 | ), 17 | migrations.AddIndex( 18 | model_name='tag', 19 | index=models.Index(fields=['tag_name', 'entity'], name='workshop_ta_tag_nam_2f9375_idx'), 20 | ), 21 | migrations.AddIndex( 22 | model_name='tag', 23 | index=models.Index(fields=['club'], name='workshop_ta_club_id_aaa1a2_idx'), 24 | ), 25 | migrations.AddIndex( 26 | model_name='tag', 27 | index=models.Index(fields=['entity'], name='workshop_ta_entity__b1a461_idx'), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /lost_and_found/migrations/0002_auto_20220215_1655.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2022-02-15 11:25 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('lost_and_found', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='lostandfound', 15 | name='status', 16 | ), 17 | migrations.RemoveField( 18 | model_name='lostandfound', 19 | name='time', 20 | ), 21 | migrations.AddField( 22 | model_name='lostandfound', 23 | name='drive_link', 24 | field=models.URLField(blank=True, null=True), 25 | ), 26 | migrations.AlterField( 27 | model_name='lostandfound', 28 | name='type_of_lost_and_found', 29 | field=models.CharField(choices=[('Lost', 'Lost'), ('Found', 'Found')], default=1, max_length=10), 30 | preserve_default=False, 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /noticeboard/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | from .models import UserProfile 3 | 4 | class AllowNoticeContact(permissions.BasePermission): 5 | message = "You are not authorized to perform this task" 6 | 7 | def has_permission(self, request, view): 8 | if request.method in permissions.SAFE_METHODS: 9 | return True 10 | if not request.user.is_authenticated: 11 | return False 12 | # pylint: disable=no-member 13 | profile = UserProfile.objects.get(user=request.user) 14 | if profile.can_post_notice: 15 | return True 16 | return False 17 | 18 | def has_object_permission(self, request, view, obj): 19 | if request.method in permissions.SAFE_METHODS: 20 | return True 21 | if not request.user.is_authenticated: 22 | return False 23 | # pylint: disable=no-member 24 | profile = UserProfile.objects.get(user=request.user) 25 | if profile.can_post_notice: 26 | return True 27 | return False 28 | -------------------------------------------------------------------------------- /authentication/migrations/0003_auto_20191009_1118.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-09 11:18 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0002_auto_20191009_0329'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='userprofile', 15 | name='course', 16 | ), 17 | migrations.RemoveField( 18 | model_name='userprofile', 19 | name='mobile_number', 20 | ), 21 | migrations.RemoveField( 22 | model_name='userprofile', 23 | name='roll_number', 24 | ), 25 | migrations.AlterField( 26 | model_name='userprofile', 27 | name='uid', 28 | field=models.CharField(max_length=64), 29 | ), 30 | migrations.AlterField( 31 | model_name='userprofile', 32 | name='year_of_joining', 33 | field=models.CharField(max_length=10), 34 | ), 35 | ] 36 | -------------------------------------------------------------------------------- /parliament_detail/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | from .models import UserProfile 3 | 4 | 5 | class AllowParliamentHead(permissions.BasePermission): 6 | message = "You are not authorized to perform this task" 7 | 8 | def has_permission(self, request, view): 9 | if request.method in permissions.SAFE_METHODS: 10 | return True 11 | if not request.user.is_authenticated: 12 | return False 13 | # pylint: disable=no-member 14 | profile = UserProfile.objects.get(user=request.user) 15 | if profile.can_add_parliament_details: 16 | return True 17 | return False 18 | 19 | def has_object_permission(self, request, view, obj): 20 | if request.method in permissions.SAFE_METHODS: 21 | return True 22 | if not request.user.is_authenticated: 23 | return False 24 | # pylint: disable=no-member 25 | profile = UserProfile.objects.get(user=request.user) 26 | if profile.can_add_parliament_details: 27 | return True 28 | return False 29 | -------------------------------------------------------------------------------- /workshop/migrations/0016_auto_20200503_0426.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-05-03 04:26 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | import workshop.models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('workshop', '0015_auto_20200503_0331'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Tag', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('name', models.CharField(max_length=50, validators=[workshop.models.validate_kebab_case])), 20 | ('club', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='workshop.Club')), 21 | ], 22 | ), 23 | migrations.AddField( 24 | model_name='workshop', 25 | name='tag', 26 | field=models.ManyToManyField(blank=True, related_name='tagged_workshops', to='workshop.Tag'), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /noticeboard/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2021-12-28 09:56 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ('authentication', '0013_userprofile_can_post_notice'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='NoticeBoard', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('title', models.CharField(max_length=50)), 20 | ('description', models.TextField(blank=True, null=True)), 21 | ('date', models.DateTimeField()), 22 | ('upvotes', models.IntegerField(default=0)), 23 | ('downvotes', models.IntegerField(default=0)), 24 | ('importance', models.IntegerField(default=0)), 25 | ('voters', models.ManyToManyField(blank=True, to='authentication.UserProfile')), 26 | ], 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /workshop/migrations/0010_auto_20200211_0929.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-11 09:29 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0009_remove_userprofile_is_admin'), 10 | ('workshop', '0009_auto_20191021_1413'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='club', 16 | name='subscribed_users', 17 | field=models.ManyToManyField(blank=True, related_name='subscriptions', to='authentication.UserProfile'), 18 | ), 19 | migrations.AddField( 20 | model_name='workshop', 21 | name='attendees', 22 | field=models.ManyToManyField(blank=True, related_name='attended_workshops', to='authentication.UserProfile'), 23 | ), 24 | migrations.AlterField( 25 | model_name='workshop', 26 | name='contacts', 27 | field=models.ManyToManyField(blank=True, related_name='organized_workshops', to='authentication.UserProfile'), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /team/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | import requests 3 | 4 | def get_github_profile_pic_url(username): 5 | """ 6 | Get the profile picture url from the github handle 7 | """ 8 | r = requests.get(f'https://api.github.com/users/{username}', timeout=0) 9 | github_user_json = r.json() 10 | return github_user_json['avatar_url'] 11 | 12 | class Role(models.Model): 13 | role = models.CharField(max_length=100) 14 | 15 | def __str__(self): 16 | return f'{self.role}' 17 | 18 | 19 | class TeamMember(models.Model): 20 | name = models.CharField(max_length=100) 21 | role = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True, 22 | blank=True, related_name='team_members') 23 | github_username = models.CharField(max_length=50) 24 | github_image_url = models.URLField(null=True, blank=True, editable=False) 25 | 26 | # pylint: disable=arguments-differ, signature-differs 27 | def save(self, *args, **kwargs): 28 | self.github_image_url = get_github_profile_pic_url(self.github_username) 29 | super().save(*args, **kwargs) 30 | 31 | def __str__(self): 32 | return f'{self.name}' 33 | -------------------------------------------------------------------------------- /workshop/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 04:53 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ('authentication', '0005_auto_20191009_1206'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Council', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('name', models.CharField(max_length=50)), 21 | ('description', models.TextField()), 22 | ('joint_secy1', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='joint_secy1', to='authentication.UserProfile')), 23 | ('joint_secy2', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='joint_secy2', to='authentication.UserProfile')), 24 | ('secy', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='authentication.UserProfile')), 25 | ], 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /workshop/migrations/0013_auto_20200303_2200.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-03-03 22:00 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('authentication', '0012_auto_20200303_2140'), 11 | ('workshop', '0012_auto_20200303_2155'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='council', 17 | name='joint_secy', 18 | ), 19 | migrations.RemoveField( 20 | model_name='council', 21 | name='secy', 22 | ), 23 | migrations.AddField( 24 | model_name='council', 25 | name='gensec', 26 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='council_gensec', to='authentication.UserProfile', verbose_name='General Secretary'), 27 | ), 28 | migrations.AddField( 29 | model_name='council', 30 | name='joint_gensec', 31 | field=models.ManyToManyField(blank=True, related_name='council_joint_gensec', to='authentication.UserProfile', verbose_name='Joint General Secretary'), 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /mess/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from grievance.models import Complaint 3 | from authentication.models import UserProfile 4 | 5 | 6 | # Create your models here. 7 | class Hostel(models.Model): 8 | name = models.CharField(max_length=200) 9 | 10 | def __str__(self): 11 | return self.name 12 | 13 | 14 | class Mess(models.Model): 15 | name = models.CharField(max_length=200) 16 | menu = models.URLField(max_length=200) 17 | hostel = models.ForeignKey(Hostel, on_delete=models.CASCADE) 18 | 19 | class Meta: 20 | verbose_name_plural = "messes" 21 | 22 | def __str__(self): 23 | return self.name 24 | 25 | 26 | class Bill(models.Model): 27 | MONTH = ((1, 'January'), (2, 'February'), (3, 'March'), (4, 'April'), (5, 'May'), (6, 'June'), 28 | (7, 'July'), (8, 'August'), (9, 'September'), (10, 'October'), (11, 'November'), (12, 'December')) 29 | 30 | user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE) 31 | mess = models.ForeignKey(Mess, on_delete=models.CASCADE) 32 | monthly_bill = models.IntegerField() 33 | extra_charges = models.IntegerField(default=0) 34 | month = models.IntegerField(choices=MONTH) 35 | 36 | def __str__(self): 37 | return '{} {}'.format(self.user_profile.name, self.mess.name) 38 | -------------------------------------------------------------------------------- /workshop/migrations/0020_auto_20200503_1950.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-05-03 19:50 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('workshop', '0019_auto_20200503_1844'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RemoveField( 15 | model_name='workshop', 16 | name='resources', 17 | ), 18 | migrations.AddField( 19 | model_name='workshop', 20 | name='link', 21 | field=models.URLField(blank=True, null=True), 22 | ), 23 | migrations.CreateModel( 24 | name='WorkshopResource', 25 | fields=[ 26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('name', models.CharField(max_length=50)), 28 | ('link', models.URLField()), 29 | ('resource_type', models.CharField(choices=[('Prerequisite', 'Prerequisite'), ('Material', 'Material')], max_length=20)), 30 | ('workshop', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='resources', to='workshop.Workshop')), 31 | ], 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /authentication/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-09 03:12 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='UserProfile', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('uid', models.CharField(editable=False, max_length=64)), 22 | ('name', models.CharField(max_length=255)), 23 | ('email', models.EmailField(max_length=255)), 24 | ('roll_number', models.CharField(max_length=8)), 25 | ('mobile_number', models.CharField(max_length=15)), 26 | ('department', models.CharField(max_length=60)), 27 | ('course', models.CharField(max_length=30)), 28 | ('year_of_joining', models.CharField(max_length=4)), 29 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 30 | ], 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /parliament_detail/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import ( 3 | ContactsListView, 4 | ContactsCreateView, 5 | ContactDetailView, 6 | CommitteeUpdatesListView, 7 | UpdatesListView, 8 | UpdatesCreateView, 9 | UpdateDetailView, 10 | SuggestionsListView, 11 | SuggestionsCreateView, 12 | SuggestionUpvoteView, 13 | SuggestionDownvoteView, 14 | SuggestionDetailView, 15 | ) 16 | 17 | urlpatterns = [ 18 | path("parliamentContact/", ContactsListView.as_view()), 19 | path("parliamentContact/create/", ContactsCreateView.as_view()), 20 | path("parliamentContact//", ContactDetailView.as_view()), 21 | path("parliamentUpdates/", UpdatesListView.as_view()), 22 | path("parliamentUpdates/committee//", CommitteeUpdatesListView.as_view()), 23 | path("parliamentUpdates/create/", UpdatesCreateView.as_view()), 24 | path("parliamentUpdates//", UpdateDetailView.as_view()), 25 | path("parliamentSuggestions/", SuggestionsListView.as_view()), 26 | path("parliamentSuggestions/create/", SuggestionsCreateView.as_view()), 27 | path("parliamentSuggestions//", SuggestionDetailView.as_view()), 28 | path("parliamentSuggestions//upvote/", SuggestionUpvoteView.as_view()), 29 | path("parliamentSuggestions//downvote/", SuggestionDownvoteView.as_view()), 30 | ] 31 | -------------------------------------------------------------------------------- /workshop/migrations/0002_auto_20191010_0507.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 05:07 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('authentication', '0005_auto_20191009_1206'), 10 | ('workshop', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RemoveField( 15 | model_name='council', 16 | name='joint_secy1', 17 | ), 18 | migrations.RemoveField( 19 | model_name='council', 20 | name='joint_secy2', 21 | ), 22 | migrations.AddField( 23 | model_name='council', 24 | name='joint_secy', 25 | field=models.ManyToManyField(related_name='councils_joint_secy', to='authentication.UserProfile'), 26 | ), 27 | migrations.AlterField( 28 | model_name='council', 29 | name='description', 30 | field=models.TextField(blank=True, null=True), 31 | ), 32 | migrations.RemoveField( 33 | model_name='council', 34 | name='secy', 35 | ), 36 | migrations.AddField( 37 | model_name='council', 38 | name='secy', 39 | field=models.ManyToManyField(related_name='councils_secy', to='authentication.UserProfile'), 40 | ), 41 | ] 42 | -------------------------------------------------------------------------------- /workshop/migrations/0004_auto_20191010_0656.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 06:56 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('authentication', '0005_auto_20191009_1206'), 11 | ('workshop', '0003_auto_20191010_0519'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='club', 17 | name='council', 18 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='clubs', to='workshop.Council'), 19 | ), 20 | migrations.CreateModel( 21 | name='Workshop', 22 | fields=[ 23 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 24 | ('title', models.CharField(max_length=50)), 25 | ('description', models.TextField(blank=True, null=True)), 26 | ('start_time', models.DateTimeField()), 27 | ('location', models.CharField(max_length=50)), 28 | ('resources', models.TextField(blank=True, null=True)), 29 | ('club', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workshops', to='workshop.Club')), 30 | ('contacts', models.ManyToManyField(blank=True, related_name='workshop_contact', to='authentication.UserProfile')), 31 | ], 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /workshop/migrations/0031_auto_20201223_0935.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2020-12-23 04:05 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0030_auto_20201222_2359'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddIndex( 14 | model_name='workshop', 15 | index=models.Index(fields=['date', 'time'], name='workshop_wo_date_62849f_idx'), 16 | ), 17 | migrations.AddIndex( 18 | model_name='workshop', 19 | index=models.Index(fields=['-date', '-time'], name='workshop_wo_date_9e5d4d_idx'), 20 | ), 21 | migrations.AddIndex( 22 | model_name='workshop', 23 | index=models.Index(fields=['club', '-date'], name='workshop_wo_club_id_e6cf8a_idx'), 24 | ), 25 | migrations.AddIndex( 26 | model_name='workshop', 27 | index=models.Index(fields=['club', 'date'], name='workshop_wo_club_id_00d260_idx'), 28 | ), 29 | migrations.AddIndex( 30 | model_name='workshop', 31 | index=models.Index(fields=['title'], name='workshop_wo_title_6c4bb6_idx'), 32 | ), 33 | migrations.AddIndex( 34 | model_name='workshop', 35 | index=models.Index(fields=['location'], name='workshop_wo_locatio_f39255_idx'), 36 | ), 37 | migrations.AddIndex( 38 | model_name='workshop', 39 | index=models.Index(fields=['audience'], name='workshop_wo_audienc_ce053f_idx'), 40 | ), 41 | ] 42 | -------------------------------------------------------------------------------- /lost_and_found/models.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from django.db import models 3 | from django.contrib.auth import get_user_model 4 | 5 | 6 | class LostAndFound(models.Model): 7 | TYPE = (('Lost', "Lost"), ('Found', "Found")) 8 | YEAR = (('1st', "1st"), ('2nd', "2nd"), 9 | ('3rd', "3rd"), ('4th', "4th"), ('5th', "5th")) 10 | COURSE = (('B.Tech', "B.Tech"), ('IDD', "IDD"), ('M.Tech', "M.Tech")) 11 | BRANCH = (('Architecture', "Architecture"), ('Ceramic', "Ceramic"), 12 | ('Chemical', "Chemical"), ('Civil', 13 | "Civil"), ('Computer Science', "Computer Science"), 14 | ('Electrical', "Electrical"), ('Electronics', 15 | "Electronics"), ('Mechanical', "Mechanical"), 16 | ('Metallurgical', "Metallurgical"), ('Mining', "Mining"), ('Pharmaceutical', "Pharmaceutical")) 17 | 18 | user = models.ForeignKey( 19 | get_user_model(), on_delete=models.CASCADE, default=None) 20 | name = models.TextField(max_length=200, blank=False, null=True) 21 | branch = models.CharField(choices=BRANCH, null=True, max_length=200) 22 | course = models.CharField(choices=COURSE, null=True, max_length=200) 23 | year = models.CharField(choices=YEAR, null=True, max_length=200) 24 | type_of_lost_and_found = models.CharField(choices=TYPE, max_length=10) 25 | description = models.TextField(max_length=4000, blank=False, null=True) 26 | drive_link = models.URLField(max_length=200, blank=True, null=True) 27 | 28 | def __str__(self): 29 | return self.name + '[' + self.type_of_lost_and_found + ']' 30 | -------------------------------------------------------------------------------- /workshop/migrations/0009_auto_20191021_1413.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-21 14:13 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('workshop', '0008_auto_20191010_1030'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='club', 16 | name='joint_secy', 17 | field=models.ManyToManyField(blank=True, related_name='club_joint_secy', to='authentication.UserProfile'), 18 | ), 19 | migrations.AlterField( 20 | model_name='club', 21 | name='secy', 22 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='club_secy', to='authentication.UserProfile'), 23 | ), 24 | migrations.AlterField( 25 | model_name='council', 26 | name='joint_secy', 27 | field=models.ManyToManyField(blank=True, related_name='council_joint_secy', to='authentication.UserProfile'), 28 | ), 29 | migrations.AlterField( 30 | model_name='council', 31 | name='secy', 32 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='council_secy', to='authentication.UserProfile'), 33 | ), 34 | migrations.AlterField( 35 | model_name='workshop', 36 | name='contacts', 37 | field=models.ManyToManyField(blank=True, related_name='workshop_contact', to='authentication.UserProfile'), 38 | ), 39 | ] 40 | -------------------------------------------------------------------------------- /noticeboard/serializers.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=too-few-public-methods 2 | # from datetime import date 3 | from rest_framework import serializers 4 | from authentication.models import UserProfile 5 | from .models import NoticeBoard 6 | 7 | class NoticeListSerializer(serializers.ModelSerializer): 8 | class Meta: 9 | model = NoticeBoard 10 | fields = ("id", "title", "date", "importance", "description") 11 | 12 | class NoticeDetailSerializer(serializers.ModelSerializer): 13 | has_voted = serializers.SerializerMethodField() 14 | 15 | def get_has_voted(self, obj): 16 | """Check if already voted""" 17 | # pylint: disable=no-member 18 | user = UserProfile.objects.get(user=self.context['request'].user) 19 | # if user in obj.voters.all(): 20 | if obj.voters.filter(id = user.id).exists(): 21 | return True 22 | return False 23 | 24 | class Meta: 25 | model = NoticeBoard 26 | read_only_fields = ("id", "upvotes", "downvotes") 27 | fields = ("id", "title", "description", "date", "upvotes", "downvotes", 28 | "importance", "has_voted") 29 | 30 | 31 | class NoticeCreateSerializer(serializers.ModelSerializer): 32 | def save(self, **kwargs): 33 | data = self.validated_data 34 | # pylint: disable=no-member 35 | noticeBoard = NoticeBoard.objects.create( 36 | title=data["title"], 37 | description=data.get("description", ""), 38 | date=data["date"], 39 | upvotes=0, 40 | downvotes=0, 41 | ) 42 | return noticeBoard 43 | class Meta: 44 | model = NoticeBoard 45 | fields = ("title", "description", "date", "importance") 46 | -------------------------------------------------------------------------------- /parliament_detail/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from authentication.models import UserProfile 3 | 4 | # Model for Parliament Contact 5 | class Contact(models.Model): 6 | profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE) 7 | designation = models.CharField(max_length=50) 8 | email = models.EmailField(max_length=50, blank=True, null=True) 9 | phone = models.CharField(max_length=13, blank=True, null=True) 10 | 11 | def __str__(self): 12 | return self.profile.name + " - " + self.designation 13 | 14 | # Model for Parliament Committee 15 | class Committee(models.Model): 16 | name = models.CharField(max_length=50) 17 | 18 | def __str__(self): 19 | return self.name 20 | 21 | # Model for Parliament Update 22 | class Update(models.Model): 23 | title=models.CharField(max_length=100) 24 | description = models.TextField() 25 | author = models.ForeignKey(UserProfile,on_delete=models.CASCADE,related_name="Update") 26 | date = models.DateTimeField(auto_now_add=True) 27 | committee = models.ForeignKey(Committee,on_delete=models.CASCADE,related_name="Committee") 28 | 29 | def __str__(self): 30 | return self.title 31 | 32 | # Model for Parliament Suggestion 33 | class Suggestion(models.Model): 34 | title=models.CharField(max_length=100) 35 | description = models.TextField() 36 | author = models.ForeignKey(UserProfile,on_delete=models.CASCADE,related_name="Suggestion") 37 | date = models.DateTimeField(auto_now_add=True) 38 | upvotes=models.IntegerField(default=0) 39 | downvotes=models.IntegerField(default=0) 40 | voters=models.ManyToManyField(UserProfile, blank=True) 41 | 42 | def __str__(self): 43 | return self.title 44 | 45 | -------------------------------------------------------------------------------- /workshop/migrations/0011_auto_20200211_1226.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-02-11 12:26 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('authentication', '0009_remove_userprofile_is_admin'), 11 | ('workshop', '0010_auto_20200211_0929'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='council', 17 | name='joint_secy', 18 | ), 19 | migrations.RemoveField( 20 | model_name='council', 21 | name='secy', 22 | ), 23 | migrations.AddField( 24 | model_name='council', 25 | name='gensec', 26 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='council_gensec', to='authentication.UserProfile', verbose_name='General Secretary'), 27 | ), 28 | migrations.AddField( 29 | model_name='council', 30 | name='joint_gensec', 31 | field=models.ManyToManyField(blank=True, related_name='council_joint_gensec', to='authentication.UserProfile', verbose_name='Joint General Secretary'), 32 | ), 33 | migrations.AlterField( 34 | model_name='club', 35 | name='joint_secy', 36 | field=models.ManyToManyField(blank=True, related_name='club_joint_secy', to='authentication.UserProfile', verbose_name='Joint Secretary'), 37 | ), 38 | migrations.AlterField( 39 | model_name='club', 40 | name='secy', 41 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='club_secy', to='authentication.UserProfile', verbose_name='Secretary'), 42 | ), 43 | ] 44 | -------------------------------------------------------------------------------- /workshop/migrations/0003_auto_20191010_0519.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 05:19 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('authentication', '0005_auto_20191009_1206'), 11 | ('workshop', '0002_auto_20191010_0507'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='council', 17 | name='joint_secy', 18 | field=models.ManyToManyField(blank=True, related_name='councils_joint_secy', to='authentication.UserProfile'), 19 | ), 20 | migrations.RemoveField( 21 | model_name='council', 22 | name='secy', 23 | ), 24 | migrations.AddField( 25 | model_name='council', 26 | name='secy', 27 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='councils_secy', to='authentication.UserProfile'), 28 | ), 29 | migrations.CreateModel( 30 | name='Club', 31 | fields=[ 32 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 33 | ('name', models.CharField(max_length=50)), 34 | ('description', models.TextField(blank=True, null=True)), 35 | ('council', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='workshop.Council')), 36 | ('joint_secy', models.ManyToManyField(blank=True, related_name='clubs_joint_secy', to='authentication.UserProfile')), 37 | ('secy', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='clubs_secy', to='authentication.UserProfile')), 38 | ], 39 | ), 40 | ] 41 | -------------------------------------------------------------------------------- /workshop/migrations/0008_auto_20191010_1030.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2019-10-10 10:30 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('workshop', '0007_auto_20191010_0706'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='club', 16 | name='joint_secy', 17 | field=models.ManyToManyField(blank=True, related_name='is_joint_secy_club', to='authentication.UserProfile'), 18 | ), 19 | migrations.AlterField( 20 | model_name='club', 21 | name='secy', 22 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='is_secy_club', to='authentication.UserProfile'), 23 | ), 24 | migrations.AlterField( 25 | model_name='council', 26 | name='joint_secy', 27 | field=models.ManyToManyField(blank=True, related_name='is_joint_secy_council', to='authentication.UserProfile'), 28 | ), 29 | migrations.AlterField( 30 | model_name='council', 31 | name='secy', 32 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='is_secy_council', to='authentication.UserProfile'), 33 | ), 34 | migrations.AlterField( 35 | model_name='workshop', 36 | name='contacts', 37 | field=models.ManyToManyField(blank=True, related_name='is_contact_workshop', to='authentication.UserProfile'), 38 | ), 39 | migrations.AlterField( 40 | model_name='workshop', 41 | name='date', 42 | field=models.DateField(default='2019-10-10'), 43 | preserve_default=False, 44 | ), 45 | ] 46 | -------------------------------------------------------------------------------- /academics/models.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=too-few-public-methods 2 | from django.db import models 3 | 4 | # Create your models here. 5 | 6 | dept_list = ( 7 | ('bce', 'Biochemical Engineering'), 8 | ('bme', 'Biomedical Engineering'), 9 | ('cer', 'Ceramic Engineering'), 10 | ('che', 'Chemical Engineering'), 11 | ('chy', 'Chemistry'), 12 | ('civ', 'Civil Engineering'), 13 | ('cse', 'Computer Science and Engineering'), 14 | ('ece', 'Electronics Engineering'), 15 | ('eee', 'Electrical Engineering'), 16 | ('mat', 'Mathematics and Computing'), 17 | ('mec', 'Mechanical Engineering'), 18 | ('met', 'Metallurgical Engineering'), 19 | ('min', 'Mining Engineering'), 20 | ('mst', 'Materials Science and Technology'), 21 | ('phe', 'Pharmaceutical Engineering and Technology'), 22 | ('phy', 'Physics'), 23 | ('hss', 'Humanistic Studies'), 24 | ) 25 | 26 | 27 | class AcademicSchedule(models.Model): 28 | department = models.CharField(max_length=60, choices=dept_list) 29 | year_of_joining = models.CharField(max_length=10) 30 | schedule_url = models.URLField() 31 | 32 | def __str__(self): 33 | return f"{self.department} {self.year_of_joining} Academic schedule" 34 | 35 | 36 | class StudyMaterials(models.Model): 37 | department = models.CharField(max_length=60, choices=dept_list) 38 | resource_url = models.URLField() 39 | 40 | class Meta: 41 | verbose_name_plural = 'Study Materials' 42 | 43 | def __str__(self): 44 | return f"{self.department} resources" 45 | 46 | 47 | class ProfsAndHODs(models.Model): 48 | department = models.CharField(max_length=60) 49 | profs_and_HODs = models.URLField(default='https://www.iitbhu.ac.in/dept') 50 | 51 | class Meta: 52 | verbose_name = 'Profs and HODs' 53 | verbose_name_plural = 'Profs and HODs' 54 | 55 | def __str__(self): 56 | return f"{self.department} Professors" 57 | -------------------------------------------------------------------------------- /academics/views.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=no-member 2 | from rest_framework import generics 3 | from django.shortcuts import get_object_or_404 4 | from .models import AcademicSchedule, StudyMaterials, ProfsAndHODs 5 | from .serializers import (AcademicScheduleSerializer, 6 | ProfsAndHODsSerializer, StudyMaterialsSerializer) 7 | 8 | class AcademicScheduleView(generics.RetrieveAPIView): 9 | """ 10 | Returns the academic schedule of the branch and year. 11 | Takes two parameters department and year of joining 12 | """ 13 | # pylint: disable=no-member 14 | queryset = AcademicSchedule.objects.all() 15 | serializer_class = AcademicScheduleSerializer 16 | 17 | def get_object(self): 18 | if getattr(self, 'swagger_fake_view', False): 19 | return None 20 | department = self.kwargs.get('dept') 21 | year_of_joining = self.kwargs.get('year') 22 | obj = get_object_or_404( 23 | self.get_queryset(), department=department, year_of_joining=year_of_joining) 24 | return obj 25 | 26 | 27 | class StudyMaterialsView(generics.RetrieveAPIView): 28 | ''' 29 | Accepts a parameter dept and returns a url of the study materials for the given department. 30 | 'dept' is the acronym of the department same as in the email id and contains lower case 31 | letters only. 32 | ''' 33 | 34 | queryset = StudyMaterials.objects.all() 35 | serializer_class = StudyMaterialsSerializer 36 | lookup_field = 'department' 37 | lookup_url_kwarg = 'dept' 38 | 39 | 40 | class ProfsAndHODsView(generics.RetrieveAPIView): 41 | ''' 42 | Accepts a parameter dept and returns a url of the professors of the given department. 43 | 'dept' is the acronym of the department same as in the email id and contains lower 44 | case letters only. 45 | ''' 46 | 47 | queryset = ProfsAndHODs.objects.all() 48 | serializer_class = ProfsAndHODsSerializer 49 | lookup_field = 'department' 50 | lookup_url_kwarg = 'dept' 51 | -------------------------------------------------------------------------------- /workshop/migrations/0012_auto_20200303_2155.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-03-03 21:55 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('authentication', '0012_auto_20200303_2140'), 11 | ('workshop', '0011_auto_20200211_1226'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='council', 17 | name='gensec', 18 | ), 19 | migrations.RemoveField( 20 | model_name='council', 21 | name='joint_gensec', 22 | ), 23 | migrations.AddField( 24 | model_name='club', 25 | name='large_image_url', 26 | field=models.URLField(blank=True, null=True), 27 | ), 28 | migrations.AddField( 29 | model_name='club', 30 | name='small_image_url', 31 | field=models.URLField(blank=True, null=True), 32 | ), 33 | migrations.AddField( 34 | model_name='council', 35 | name='joint_secy', 36 | field=models.ManyToManyField(blank=True, related_name='council_joint_secy', to='authentication.UserProfile'), 37 | ), 38 | migrations.AddField( 39 | model_name='council', 40 | name='large_image_url', 41 | field=models.URLField(blank=True, null=True), 42 | ), 43 | migrations.AddField( 44 | model_name='council', 45 | name='secy', 46 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='council_secy', to='authentication.UserProfile'), 47 | ), 48 | migrations.AddField( 49 | model_name='council', 50 | name='small_image_url', 51 | field=models.URLField(blank=True, null=True), 52 | ), 53 | migrations.AddField( 54 | model_name='workshop', 55 | name='image_url', 56 | field=models.URLField(blank=True, null=True), 57 | ), 58 | ] 59 | -------------------------------------------------------------------------------- /mess/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2022-02-28 10:56 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ('authentication', '0014_userprofile_can_add_parliament_details'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Hostel', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('name', models.CharField(max_length=200)), 21 | ], 22 | ), 23 | migrations.CreateModel( 24 | name='Mess', 25 | fields=[ 26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('name', models.CharField(max_length=200)), 28 | ('menu', models.URLField()), 29 | ('hostel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mess.Hostel')), 30 | ], 31 | options={ 32 | 'verbose_name_plural': 'messes', 33 | }, 34 | ), 35 | migrations.CreateModel( 36 | name='Bill', 37 | fields=[ 38 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 39 | ('monthly_bill', models.IntegerField()), 40 | ('extra_charges', models.IntegerField(default=0)), 41 | ('month', models.IntegerField(choices=[(1, 'January'), (2, 'February'), (3, 'March'), (4, 'April'), (5, 'May'), (6, 'June'), (7, 'July'), (8, 'August'), (9, 'September'), (10, 'October'), (11, 'November'), (12, 'December')])), 42 | ('mess', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mess.Mess')), 43 | ('user_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='authentication.UserProfile')), 44 | ], 45 | ), 46 | ] 47 | -------------------------------------------------------------------------------- /lost_and_found/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2022-02-10 15:03 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='LostAndFound', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('name', models.TextField(max_length=200, null=True)), 22 | ('branch', models.CharField(choices=[('Architecture', 'Architecture'), ('Ceramic', 'Ceramic'), ('Chemical', 'Chemical'), ('Civil', 'Civil'), ('Computer Science', 'Computer Science'), ('Electrical', 'Electrical'), ('Electronics', 'Electronics'), ('Mechanical', 'Mechanical'), ('Metallurgical', 'Metallurgical'), ('Mining', 'Mining'), ('Pharmaceutical', 'Pharmaceutical')], max_length=200, null=True)), 23 | ('course', models.CharField(choices=[('B.Tech', 'B.Tech'), ('IDD', 'IDD'), ('M.Tech', 'M.Tech')], max_length=200, null=True)), 24 | ('year', models.CharField(choices=[('1st', '1st'), ('2nd', '2nd'), ('3rd', '3rd'), ('4th', '4th'), ('5th', '5th')], max_length=200, null=True)), 25 | ('type_of_lost_and_found', models.CharField(choices=[('Security', 'Security'), ('Health&Hygiene', 'Health&Hygiene'), ('HostelMess', 'HostelMess'), ('Academics', 'Academics'), ('Council', 'Council'), ('Others', 'Others')], max_length=200, null=True)), 26 | ('description', models.TextField(max_length=4000, null=True)), 27 | ('time', models.DateField(auto_now=True)), 28 | ('status', models.IntegerField(choices=[(1, 'Closed'), (2, 'Registered'), (3, 'Pending')], default=3)), 29 | ('user', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 30 | ], 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /grievance/models.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from django.db import models 3 | from django.contrib.auth import get_user_model 4 | 5 | class Complaint(models.Model): 6 | STATUS = ((1, 'Closed'), (2, 'Registered'), (3, 'Pending')) 7 | TYPE = (('Security', "Security"), ('Health&Hygiene', "Health&Hygiene"), 8 | ('HostelMess', "HostelMess"), ('Academics', "Academics"), 9 | ('Council', "Council"), ('Others', "Others")) 10 | YEAR = (('1st', "1st"), ('2nd', "2nd"), 11 | ('3rd', "3rd"), ('4th', "4th"), ('5th', "5th")) 12 | COURSE = (('B.Tech', "B.Tech"), ('IDD', "IDD"), ('M.Tech', "M.Tech")) 13 | BRANCH = (('Architecture', "Architecture"), ('Ceramic', "Ceramic"), 14 | ('Chemical', "Chemical"), ('Civil', "Civil"), ('Computer Science', "Computer Science"), 15 | ('Electrical',"Electrical"), ('Electronics', "Electronics"), ('Mechanical', "Mechanical"), 16 | ('Metallurgical', "Metallurgical"), ('Mining', "Mining"), ('Pharmaceutical', "Pharmaceutical")) 17 | 18 | user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, default=None) 19 | name = models.TextField(max_length=200, blank=False, null=True) 20 | branch = models.CharField(choices=BRANCH, null=True, max_length=200) 21 | course = models.CharField(choices=COURSE, null=True, max_length=200) 22 | year = models.CharField(choices=YEAR, null=True, max_length=200) 23 | type_of_complaint = models.CharField(choices=TYPE, null=True, max_length=200) 24 | description = models.TextField(max_length=4000, blank=False, null=True) 25 | drive_link = models.URLField(max_length=400, blank=True) 26 | time = models.DateField(auto_now=True) 27 | status = models.IntegerField(choices=STATUS, default=3) 28 | 29 | def __init__(self, *args, **kwargs): 30 | super(Complaint, self).__init__(*args, **kwargs) 31 | self.__status = self.status 32 | 33 | def save(self, *args, **kwargs): 34 | if self.status and not self.__status: 35 | self.active_from = datetime.now() 36 | super(Complaint, self).save(*args, **kwargs) 37 | 38 | def __str__(self): 39 | return self.name + '[' + self.type_of_complaint + ']' 40 | -------------------------------------------------------------------------------- /workshops/urls.py: -------------------------------------------------------------------------------- 1 | """workshops URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path, include 18 | from rest_framework import permissions 19 | from drf_yasg2.views import get_schema_view 20 | from drf_yasg2 import openapi 21 | 22 | admin.site.site_header = 'IIT BHU Workshops App Backend Administration' 23 | 24 | schema_view = get_schema_view( 25 | openapi.Info( 26 | title="IIT BHU Workshops App API", 27 | default_version='v1', 28 | description= 29 | """ 30 | This is the official IIT BHU Workshops App API developed using Django Rest Framework. 31 | 32 | The source code can be found [here](https://github.com/IIT-BHU-InstiApp/lite-hai-backend). 33 | """, 34 | ), 35 | public=True, 36 | permission_classes=(permissions.AllowAny,), 37 | ) 38 | 39 | urlpatterns = [ 40 | path('admin/', admin.site.urls), 41 | path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), 42 | path('', include('authentication.urls')), 43 | path('', include('academics.urls')), 44 | path('', include('config.urls')), 45 | path('', include('workshop.urls')), 46 | path('', include('team.urls')), 47 | path('', include('noticeboard.urls')), 48 | path('', include('grievance.urls')), 49 | path('', include('parliament_detail.urls')), 50 | path('', include('lost_and_found.urls')), 51 | path('', include('mess.urls')), 52 | path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), 53 | ] 54 | -------------------------------------------------------------------------------- /grievance/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2021-12-08 13:02 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Complaint', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('name', models.TextField(max_length=200, null=True)), 22 | ('branch', models.CharField(choices=[('Architecture', 'Architecture'), ('Ceramic', 'Ceramic'), ('Chemical', 'Chemical'), ('Civil', 'Civil'), ('Computer Science', 'Computer Science'), ('Electrical', 'Electrical'), ('Electronics', 'Electronics'), ('Mechanical', 'Mechanical'), ('Metallurgical', 'Metallurgical'), ('Mining', 'Mining'), ('Pharmaceutical', 'Pharmaceutical')], max_length=200, null=True)), 23 | ('course', models.CharField(choices=[('B.Tech', 'B.Tech'), ('IDD', 'IDD'), ('M.Tech', 'M.Tech')], max_length=200, null=True)), 24 | ('year', models.CharField(choices=[('1st', '1st'), ('2nd', '2nd'), ('3rd', '3rd'), ('4th', '4th'), ('5th', '5th')], max_length=200, null=True)), 25 | ('type_of_complaint', models.CharField(choices=[('Security', 'Security'), ('Health&Hygiene', 'Health&Hygiene'), ('HostelMess', 'HostelMess'), ('Academics', 'Academics'), ('Council', 'Council'), ('Others', 'Others')], max_length=200, null=True)), 26 | ('description', models.TextField(max_length=4000, null=True)), 27 | ('drive_link', models.URLField(blank=True, max_length=400)), 28 | ('time', models.DateField(auto_now=True)), 29 | ('status', models.IntegerField(choices=[(1, 'Closed'), (2, 'Registered'), (3, 'Pending')], default=3)), 30 | ('user', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 31 | ], 32 | ), 33 | ] -------------------------------------------------------------------------------- /keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "service_account", 3 | "project_id": "lite-hai", 4 | "private_key_id": "95ada3203274cb0e2fb537d82d1ef7d748c0a4f7", 5 | "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCXmqEAR2YWGxc0\nKiYod6j15zL/YzazyAdqcElBVq4Nb88RtXpud9VFaTpNYHJxJcapZMM9aQKTWy6t\n4jjRpbXWwaixjGjwu30gbw4lQvtgbfdW+gT8FKCe13UYGo912hkR7G9JOMTiDvBV\n6/Ei3ndP2OafLimorMPIXXMhcv8RPsODwpKjzANRDHSqPuVwce3RW9ykbVyEzkbY\n2aq8Chp+LOBOu71zB5DdIpyUa+YRzsSuV+ZAC5XgpaimnIT0RP2s12pfUBmKxsvX\nlq4Q+TMzGZI9IqpahBDClX1wErNq2w0HE+ST3GE6rarQir3DMSVO88g7IpKp13Qm\nos/E3g+DAgMBAAECggEAF1alnG5hZ9vJya0HbMlnCFwMPMagQDL1+UvJ6zYV21mw\nDfDbJTBrc6EMaacEVyjSmXc6mzSUQe0SlZAy4Qtan/H2L0cHTLAARkLycYgLPMAR\nCKG6rLfcNjfC/e/wz9rAa0LzqtkDbi2QkBmfaJfI1FD2x+CKZz4Zcbn5JFgYriW3\ntFm6WpvRpHUL3e2TjaQ6hxrWmZmuega5FpnK26AqoG6AkcTWtjvk8qwaipybOuC/\nTgjBqV9rmR2g8A5pWx3YS80if96bKWnFepo2CNQad3q6XP7Q+hxpXIBrRm0r5TbT\npwAigWNlegnUeYyge6JX2ibFv2FQNN/djgQBasGeSQKBgQDKNBeBmRmdPL0QdUIo\nKa7jgqBnRng/IcCp+jvZjcmFXQTEBh+VDWGHM1pZX8ao90Th+v7m8/1YSFCw2Vm/\npH0/XGT3qbt1eC1BFLdGiq/IyZYQH2Wsl81TWrvSxWcsCAkzkdH/rDTc/Cpm5Xux\nLfhGlWo8sRIbCRgYL9YNTy0+fQKBgQC/8EAYuLvh33awE47oYbB8yY8wIpmjkqzo\nre0tBkmO/8lQA8JvauK6Z8HjX+eYnbLCOii3yhZI8vZypWodmbCq9nWWO6eyNKDT\nwNNCZrFDwKTHHZTZmrBb5RpM4z478FapRuD6NLfcaIzLACriQI2OgSPZFDMjjvvX\nIh/s1zPl/wKBgCzvTpn6T/rlWI6jwEP0n2znxoWs32QIOCyN82bxX2tHtJtrUPFq\nu9Wzz8w0wI0kBibCBIuGhTJtP6FNa+huwXanLbjr+0CrqELiO6htgYr5YWPL1mh4\ng6SWcU7xl2/tiT3wld5fgo/pafLb5JUHRjlJUwaRwxhG+RfG6aajhcZxAoGBAJrx\nbjzGvF0NkPl5AG9VlSxXZfDcrZxfZpf697DWF4GJuVCPiGF7LoZ+BgXwQLxx6YFj\ng8VCLRU8lXhdUjmM/RI2HRxnEewJEh9+1MwQrF7eX+ahWa0EdAPrAX06IN4wGTVT\nk4BIGHikKawieXvl0qBMXcz6woGdBm5YDN+bpjivAoGBAJ5HlBLCsYtkpqljSksQ\nDtHeApq+QGhQdk92idm7/8VmbXMMYRU4c8Voh1oIG5j5ZD7ZySsIxoFb5JlI27nx\nYHRVOgX8GsjbFoddvl0sp9qDGWXixvsTHjW3aNLr47KynRppiQOxgwW/YuWrOE18\ngIizaUCsv4EdEC82nvM+xBiP\n-----END PRIVATE KEY-----\n", 6 | "client_email": "lite-hai@lite-hai.iam.gserviceaccount.com", 7 | "client_id": "100235400634715727776", 8 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 9 | "token_uri": "https://oauth2.googleapis.com/token", 10 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", 11 | "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lite-hai%40lite-hai.iam.gserviceaccount.com" 12 | } 13 | -------------------------------------------------------------------------------- /mess/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import Bill, Mess, Hostel 3 | from authentication.models import UserProfile 4 | 5 | 6 | class HostelListSerializer(serializers.ModelSerializer): 7 | """ 8 | Serializer for hostel list view. 9 | """ 10 | class Meta: 11 | model = Hostel 12 | fields = ('id', 'name',) 13 | 14 | 15 | class MessDetailSerializer(serializers.ModelSerializer): 16 | """ 17 | Serializer for mess list and detail view. 18 | """ 19 | class Meta: 20 | model = Mess 21 | fields = ('id', 'name', 'menu',) 22 | 23 | 24 | class MessBillSerializer(serializers.Serializer): 25 | """ 26 | Serializer for showing the billing of individual students. 27 | """ 28 | 29 | def validate(self, data): 30 | """ 31 | Checks if the current user is subscribed to the mess 32 | with given id. Raises error if not subscribed. 33 | """ 34 | mess_id = self.context['mess_id'] 35 | mess = Mess.objects.filter(id=mess_id) 36 | if not mess: 37 | raise serializers.ValidationError( 38 | 'Mess with given id does not exist.') 39 | 40 | mess = mess.first() 41 | month = self.context['month'] 42 | user = self.context['request'].user 43 | user_profile = UserProfile.objects.filter(user=user).first() 44 | 45 | bill = Bill.objects.filter( 46 | user_profile=user_profile, mess=mess, month=month) 47 | if not bill: 48 | raise serializers.ValidationError( 49 | 'Bill details not found for the student with given mess and month.') 50 | 51 | data['bill'] = bill.first() 52 | return data 53 | 54 | def get_bill_details(self): 55 | """ 56 | Fetches the billing details of the current user 57 | and returns the serialized bill details. 58 | """ 59 | data = self.validated_data 60 | bill = data.get('bill') 61 | serialized_bill = BillSerializer(bill) 62 | return serialized_bill.data 63 | 64 | 65 | class BillSerializer(serializers.ModelSerializer): 66 | """ 67 | Helper serializer for serializing the bill objects. 68 | """ 69 | name = serializers.CharField(source='user_profile.name') 70 | mess = serializers.CharField(source='mess.name') 71 | 72 | class Meta: 73 | model = Bill 74 | fields = ('name', 'mess', 'monthly_bill', 'extra_charges', 'month',) 75 | -------------------------------------------------------------------------------- /workshop/migrations/0015_auto_20200503_0331.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2020-05-03 03:31 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('workshop', '0014_auto_20200407_0831'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='club', 15 | name='facebook_url', 16 | field=models.URLField(blank=True, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='club', 20 | name='instagram_url', 21 | field=models.URLField(blank=True, null=True), 22 | ), 23 | migrations.AddField( 24 | model_name='club', 25 | name='linkedin_url', 26 | field=models.URLField(blank=True, null=True), 27 | ), 28 | migrations.AddField( 29 | model_name='club', 30 | name='twitter_url', 31 | field=models.URLField(blank=True, null=True), 32 | ), 33 | migrations.AddField( 34 | model_name='club', 35 | name='website_url', 36 | field=models.URLField(blank=True, null=True), 37 | ), 38 | migrations.AddField( 39 | model_name='club', 40 | name='youtube_url', 41 | field=models.URLField(blank=True, null=True), 42 | ), 43 | migrations.AddField( 44 | model_name='council', 45 | name='facebook_url', 46 | field=models.URLField(blank=True, null=True), 47 | ), 48 | migrations.AddField( 49 | model_name='council', 50 | name='instagram_url', 51 | field=models.URLField(blank=True, null=True), 52 | ), 53 | migrations.AddField( 54 | model_name='council', 55 | name='linkedin_url', 56 | field=models.URLField(blank=True, null=True), 57 | ), 58 | migrations.AddField( 59 | model_name='council', 60 | name='twitter_url', 61 | field=models.URLField(blank=True, null=True), 62 | ), 63 | migrations.AddField( 64 | model_name='council', 65 | name='website_url', 66 | field=models.URLField(blank=True, null=True), 67 | ), 68 | migrations.AddField( 69 | model_name='council', 70 | name='youtube_url', 71 | field=models.URLField(blank=True, null=True), 72 | ), 73 | ] 74 | -------------------------------------------------------------------------------- /workshop/migrations/0022_auto_20201120_1230.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-11-20 07:00 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('workshop', '0021_entity_event_eventresource'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='event', 16 | name='club', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='club_events', to='workshop.Club'), 18 | ), 19 | migrations.AddField( 20 | model_name='tag', 21 | name='entity', 22 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='entity_tags', to='workshop.Entity'), 23 | ), 24 | migrations.AddField( 25 | model_name='workshop', 26 | name='entity', 27 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='entity_workshops', to='workshop.Entity'), 28 | ), 29 | migrations.AddField( 30 | model_name='workshopresource', 31 | name='event', 32 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='event_resources', to='workshop.Event'), 33 | ), 34 | migrations.AlterField( 35 | model_name='event', 36 | name='entity', 37 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='entity_events', to='workshop.Entity'), 38 | ), 39 | migrations.AlterField( 40 | model_name='tag', 41 | name='club', 42 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='workshop.Club'), 43 | ), 44 | migrations.AlterField( 45 | model_name='workshop', 46 | name='club', 47 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='workshops', to='workshop.Club'), 48 | ), 49 | migrations.AlterField( 50 | model_name='workshopresource', 51 | name='workshop', 52 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='resources', to='workshop.Workshop'), 53 | ), 54 | migrations.DeleteModel( 55 | name='EventResource', 56 | ), 57 | ] 58 | -------------------------------------------------------------------------------- /authentication/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth import get_user_model 3 | 4 | class UserProfile(models.Model): 5 | uid = models.CharField(max_length=64) 6 | user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE) 7 | name = models.CharField(max_length=255) 8 | email = models.EmailField(max_length=255) 9 | phone_number = models.CharField(max_length=15, null=True, blank=True) 10 | department = models.CharField(max_length=60) 11 | year_of_joining = models.CharField(max_length=10) 12 | photo_url = models.URLField(null=True, blank=True, editable=False) 13 | can_post_notice = models.BooleanField(default=False) 14 | can_add_parliament_details = models.BooleanField(default=False) 15 | 16 | # pylint: disable=invalid-str-returned 17 | def __str__(self): 18 | return self.name 19 | 20 | def get_council_privileges(self): 21 | """ 22 | Get the privileges of the user for managing Council details 23 | Councils - General Secretary / Joint General Secretary 24 | """ 25 | # pylint: disable=no-member 26 | councils = self.council_gensec.all() 27 | councils = councils.union(self.council_joint_gensec.all()) 28 | return councils 29 | 30 | def get_club_privileges(self): 31 | """ 32 | Get the privileges of the user for creating workshops 33 | Clubs - Secretary / Joint Secretary, 34 | Councils - General Secretary / Joint General Secretary 35 | """ 36 | # pylint: disable=no-member 37 | clubs = self.club_secy.all().select_related('council') 38 | clubs = clubs.union(self.club_joint_secy.all().select_related('council')) 39 | council_gensec = self.council_gensec 40 | council_joint_gensec = self.council_joint_gensec 41 | for council in council_gensec.all(): 42 | clubs = clubs.union(council.clubs.all().select_related('council')) 43 | for council in council_joint_gensec.all(): 44 | clubs = clubs.union(council.clubs.all().select_related('council')) 45 | return clubs 46 | 47 | def get_workshop_privileges(self): 48 | """ 49 | Get the privileges of the user for modifying workshops 50 | """ 51 | # pylint: disable=no-member 52 | workshops = self.organized_workshops.all() 53 | return workshops 54 | 55 | def get_entity_privileges(self): 56 | """ 57 | Get the privileges of the user for creating events 58 | Entities - Point of Contact, 59 | """ 60 | # pylint: disable=no-member 61 | entities = self.entity_point_of_contact.all() 62 | return entities 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/django 3 | # Edit at https://www.gitignore.io/?templates=django 4 | 5 | .env 6 | venv/ 7 | .vscode 8 | 9 | ### Django ### 10 | *.log 11 | *.pot 12 | *.pyc 13 | __pycache__/ 14 | local_settings.py 15 | db.sqlite3 16 | db.sqlite3-journal 17 | media 18 | 19 | # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ 20 | # in your Git repository. Update and uncomment the following line accordingly. 21 | # /staticfiles/ 22 | 23 | ### Django.Python Stack ### 24 | # Byte-compiled / optimized / DLL files 25 | *.py[cod] 26 | *$py.class 27 | 28 | # C extensions 29 | *.so 30 | 31 | # Distribution / packaging 32 | .Python 33 | build/ 34 | env/ 35 | develop-eggs/ 36 | dist/ 37 | downloads/ 38 | eggs/ 39 | .eggs/ 40 | lib/ 41 | lib64/ 42 | parts/ 43 | sdist/ 44 | var/ 45 | wheels/ 46 | pip-wheel-metadata/ 47 | share/python-wheels/ 48 | *.egg-info/ 49 | .installed.cfg 50 | *.egg 51 | MANIFEST 52 | 53 | # PyInstaller 54 | # Usually these files are written by a python script from a template 55 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 56 | *.manifest 57 | *.spec 58 | 59 | # Installer logs 60 | pip-log.txt 61 | pip-delete-this-directory.txt 62 | 63 | # Unit test / coverage reports 64 | htmlcov/ 65 | .tox/ 66 | .nox/ 67 | .coverage 68 | .coverage.* 69 | .cache 70 | nosetests.xml 71 | coverage.xml 72 | *.cover 73 | .hypothesis/ 74 | .pytest_cache/ 75 | 76 | # Translations 77 | *.mo 78 | 79 | # Scrapy stuff: 80 | .scrapy 81 | 82 | # Sphinx documentation 83 | docs/_build/ 84 | 85 | # PyBuilder 86 | target/ 87 | 88 | # pyenv 89 | .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # celery beat schedule file 99 | celerybeat-schedule 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Spyder project settings 105 | .spyderproject 106 | .spyproject 107 | 108 | # Rope project settings 109 | .ropeproject 110 | 111 | # Mr Developer 112 | .mr.developer.cfg 113 | .project 114 | .pydevproject 115 | 116 | # mkdocs documentation 117 | /site 118 | 119 | # mypy 120 | .mypy_cache/ 121 | .dmypy.json 122 | dmypy.json 123 | 124 | # Pyre type checker 125 | .pyre/ 126 | 127 | # End of https://www.gitignore.io/api/django 128 | service_account.json 129 | script*.py 130 | -------------------------------------------------------------------------------- /mess/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import status, permissions 2 | from rest_framework.response import Response 3 | from rest_framework.generics import GenericAPIView 4 | from .models import ( 5 | Bill, Mess, Hostel 6 | ) 7 | from .serializers import ( 8 | HostelListSerializer, MessDetailSerializer, MessBillSerializer 9 | ) 10 | 11 | # Create your views here. 12 | 13 | 14 | class HostelListView(GenericAPIView): 15 | """ 16 | get: 17 | Returns a list of all hostels. 18 | """ 19 | permission_classes = [] 20 | queryset = Hostel.objects.all() 21 | serializer_class = HostelListSerializer 22 | 23 | def get(self, request, *args, **kwargs): 24 | serializer = self.get_serializer(self.get_queryset(), many=True) 25 | return Response(serializer.data, status=status.HTTP_200_OK) 26 | 27 | 28 | class MessListView(GenericAPIView): 29 | """ 30 | get: 31 | Returns a list of (id, name) of all mess in a hostel. 32 | """ 33 | permission_classes = [] 34 | serializer_class = MessDetailSerializer 35 | 36 | def get_queryset(self): 37 | id = self.kwargs.get('pk') 38 | hostel = Hostel.objects.filter(id=id).first() 39 | return Mess.objects.filter(hostel=hostel).all() 40 | 41 | def get(self, request, pk): 42 | serializer = self.get_serializer(self.get_queryset(), many=True) 43 | return Response(serializer.data, status=status.HTTP_200_OK) 44 | 45 | 46 | class MessDetailView(GenericAPIView): 47 | """ 48 | get: 49 | Returns mess details with given id. 50 | """ 51 | permission_classes = [] 52 | serializer_class = MessDetailSerializer 53 | 54 | def get_queryset(self): 55 | id = self.kwargs.get('pk') 56 | return Mess.objects.filter(id=id).first() 57 | 58 | def get(self, request, pk): 59 | serializer = self.get_serializer(self.get_queryset()) 60 | return Response(serializer.data, status=status.HTTP_200_OK) 61 | 62 | 63 | class MessBillView(GenericAPIView): 64 | """ 65 | get: 66 | Returns bill details of the student with given mess id for given month. 67 | """ 68 | permission_classes = [permissions.IsAuthenticated] 69 | serializer_class = MessBillSerializer 70 | queryset = Bill.objects.all() 71 | 72 | def get_serializer_context(self): 73 | context = super().get_serializer_context() 74 | context.update({ 75 | 'mess_id': self.kwargs.get('pk'), 76 | 'month': self.kwargs.get('month') 77 | }) 78 | return context 79 | 80 | def get(self, request, pk, month): 81 | serializer = self.get_serializer(data=request.data) 82 | serializer.is_valid(raise_exception=True) 83 | bill = serializer.get_bill_details() 84 | return Response(bill, status=status.HTTP_200_OK) 85 | -------------------------------------------------------------------------------- /parliament_detail/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2022-03-01 11:43 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ('authentication', '0014_userprofile_can_add_parliament_details'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Committee', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('name', models.CharField(max_length=50)), 21 | ], 22 | ), 23 | migrations.CreateModel( 24 | name='Update', 25 | fields=[ 26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('title', models.CharField(max_length=100)), 28 | ('description', models.TextField()), 29 | ('date', models.DateTimeField(auto_now_add=True)), 30 | ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='Update', to='authentication.UserProfile')), 31 | ('committee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='Committee', to='parliament_detail.Committee')), 32 | ], 33 | ), 34 | migrations.CreateModel( 35 | name='Suggestion', 36 | fields=[ 37 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 38 | ('title', models.CharField(max_length=100)), 39 | ('description', models.TextField()), 40 | ('date', models.DateTimeField(auto_now_add=True)), 41 | ('upvotes', models.IntegerField(default=0)), 42 | ('downvotes', models.IntegerField(default=0)), 43 | ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='Suggestion', to='authentication.UserProfile')), 44 | ('voters', models.ManyToManyField(blank=True, to='authentication.UserProfile')), 45 | ], 46 | ), 47 | migrations.CreateModel( 48 | name='Contact', 49 | fields=[ 50 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 51 | ('designation', models.CharField(max_length=50)), 52 | ('email', models.EmailField(blank=True, max_length=50, null=True)), 53 | ('phone', models.CharField(blank=True, max_length=13, null=True)), 54 | ('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='authentication.UserProfile')), 55 | ], 56 | ), 57 | ] 58 | -------------------------------------------------------------------------------- /lost_and_found/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import LostAndFound 3 | 4 | 5 | class CreateLostAndFoundSerializer(serializers.Serializer): 6 | TYPE = (('Lost', "Lost"), ('Found', "Found")) 7 | YEAR = (('1st', "1st"), ('2nd', "2nd"), 8 | ('3rd', "3rd"), ('4th', "4th"), ('5th', "5th")) 9 | COURSE = (('B.Tech', "B.Tech"), ('IDD', "IDD"), ('M.Tech', "M.Tech")) 10 | BRANCH = (('Architecture', "Architecture"), ('Ceramic', "Ceramic"), 11 | ('Chemical', "Chemical"), ('Civil', 12 | "Civil"), ('Computer Science', "Computer Science"), 13 | ('Electrical', "Electrical"), ('Electronics', 14 | "Electronics"), ('Mechanical', "Mechanical"), 15 | ('Metallurgical', "Metallurgical"), ('Mining', "Mining"), ('Pharmaceutical', "Pharmaceutical")) 16 | 17 | name = serializers.CharField(max_length=200) 18 | branch = serializers.ChoiceField(choices=BRANCH) 19 | course = serializers.ChoiceField(choices=COURSE) 20 | year = serializers.ChoiceField(choices=YEAR) 21 | type_of_lost_and_found = serializers.ChoiceField(choices=TYPE) 22 | description = serializers.CharField(max_length=4000) 23 | drive_link = serializers.URLField( 24 | max_length=400, allow_blank=True, required=False) 25 | 26 | def save(self): 27 | """ 28 | Takes the validated data, creates a new lost and found object and returns it. 29 | """ 30 | data = self.validated_data 31 | name = data.get('name') 32 | branch = data.get('branch') 33 | course = data.get('course') 34 | year = data.get('year') 35 | type_of_lost_and_found = data.get( 36 | 'type_of_lost_and_found') 37 | description = data.get('description') 38 | drive_link = data.get('drive_link', None) 39 | user = self.context["request"].user 40 | 41 | # pylint: disable=no-member 42 | lost_and_found = LostAndFound.objects.create( 43 | user=user, name=name, branch=branch, course=course, 44 | year=year, type_of_lost_and_found=type_of_lost_and_found, 45 | description=description, drive_link=drive_link) 46 | lost_and_found.save() 47 | return lost_and_found 48 | 49 | 50 | class LostAndFoundListSerializer(serializers.Serializer): 51 | def get_list(self): 52 | """ 53 | Returns an array consisting of lost and found objects created by the user. 54 | """ 55 | user = self.context["request"].user 56 | # pylint: disable=no-member 57 | user_lost_and_found = LostAndFound.objects.filter(user=user) 58 | return user_lost_and_found 59 | 60 | 61 | class LostAndFoundSerializer(serializers.ModelSerializer): 62 | class Meta: 63 | model = LostAndFound 64 | fields = ('id', 'name', 'branch', 'course', 'year', 'type_of_lost_and_found', 65 | 'description', 'drive_link') 66 | -------------------------------------------------------------------------------- /authentication/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | from rest_framework import generics 3 | from rest_framework import status 4 | from rest_framework.response import Response 5 | from rest_framework.authtoken.models import Token 6 | from workshop.permissions import AllowAnyClubOrEntityHead 7 | from .models import UserProfile 8 | from .serializers import ( 9 | LoginSerializer, ProfileSerializer, ResponseSerializer, ProfileSearchSerializer) 10 | 11 | def create_auth_token(user): 12 | """ 13 | Returns the token required for authentication for a user. 14 | """ 15 | # pylint: disable=no-member 16 | token, _ = Token.objects.get_or_create(user=user) 17 | return token 18 | 19 | class LoginView(generics.GenericAPIView): 20 | authentication_classes = [] 21 | permission_classes = (permissions.AllowAny, ) 22 | serializer_class = LoginSerializer 23 | 24 | def post(self, request): 25 | """ 26 | Checks the credentials (taking firebase **idToken** as input)\ 27 | and returns the **REST Token** (Authentication Token),\ 28 | if the credentials are valid. 29 | """ 30 | serializer = self.get_serializer(data=request.data) 31 | serializer.is_valid(raise_exception=True) 32 | user = serializer.validated_data['user'] 33 | token = create_auth_token(user) 34 | response = ResponseSerializer({'token': token}) 35 | return Response(response.data, status.HTTP_200_OK) 36 | 37 | 38 | class ProfileView(generics.RetrieveUpdateAPIView): 39 | """ 40 | get: 41 | Returns the Name, Email, Phone Number, Department, Year of Joining\ 42 | and Photo URL of the user. Also returns the subscriptions and\ 43 | club privileges of the user. 44 | 45 | put: 46 | Updates the name, phone_number and photo of User Profile and\ 47 | returns all the fields. (Full update) 48 | 49 | patch: 50 | Updates the name, phone_number and photo of User Profile and\ 51 | returns all the fields. (Partial update) 52 | """ 53 | permission_classes = (permissions.IsAuthenticated, ) 54 | serializer_class = ProfileSerializer 55 | 56 | def get_object(self): 57 | # pylint: disable=no-member 58 | return UserProfile.objects.get(user=self.request.user) 59 | 60 | 61 | class ProfileSearchView(generics.GenericAPIView): 62 | permission_classes = (AllowAnyClubOrEntityHead, ) 63 | serializer_class = ProfileSearchSerializer 64 | 65 | def post(self, request): 66 | """ 67 | Search a user based on Name or Email. (Only Top 10 results) 68 | Only Club POR holders/Entity Points of Contact can perform this action. 69 | (Can be used to search profile while adding contacts for a workshop) 70 | """ 71 | serializer = self.get_serializer(data=request.data) 72 | serializer.is_valid(raise_exception=True) 73 | profile = serializer.save() 74 | response = ProfileSerializer(profile, many=True) 75 | return Response(response.data, status.HTTP_200_OK) 76 | -------------------------------------------------------------------------------- /lost_and_found/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import status, permissions 2 | from rest_framework.response import Response 3 | from rest_framework.generics import GenericAPIView 4 | from .models import LostAndFound 5 | from .serializers import ( 6 | CreateLostAndFoundSerializer, 7 | LostAndFoundSerializer, 8 | LostAndFoundListSerializer) 9 | from googleapiclient.discovery import build 10 | from google.oauth2 import service_account 11 | 12 | SCOPES = ['https://www.googleapis.com/auth/spreadsheets'] 13 | SERVICE_ACCOUNT_FILE = 'keys.json' 14 | 15 | cred = None 16 | cred = service_account.Credentials.from_service_account_file( 17 | SERVICE_ACCOUNT_FILE, scopes=SCOPES) 18 | 19 | LOST_AND_FOUND_SPREADSHEET_ID = '1Hch-gohmuAeAeJFwaozb1xz_Oj7DLa6C0qOhAuk3t-o' 20 | 21 | 22 | class CreateLostAndFoundView(GenericAPIView): 23 | """ 24 | post: 25 | Creates a new lost and found object and returns the 26 | Id, Name, Branch, Course, Year, Type and Description of the object. 27 | """ 28 | permission_classes = (permissions.IsAuthenticated,) 29 | # pylint: disable=no-member 30 | queryset = LostAndFound.objects.all() 31 | serializer_class = CreateLostAndFoundSerializer 32 | 33 | def post(self, request, *args, **kwargs): 34 | serializer = self.get_serializer(data=request.data) 35 | serializer.is_valid(raise_exception=True) 36 | complaint = serializer.save() 37 | complaint_dict = LostAndFoundSerializer(complaint) 38 | service = build('sheets', 'v4', credentials=cred) 39 | sheet = service.spreadsheets() 40 | sheet.values().append( 41 | spreadsheetId=LOST_AND_FOUND_SPREADSHEET_ID, 42 | range="lost_and_found!A1:H1", 43 | valueInputOption="USER_ENTERED", 44 | insertDataOption="INSERT_ROWS", 45 | body={ 46 | "values": [[ 47 | complaint_dict.data['id'], 48 | complaint_dict.data['name'], 49 | complaint_dict.data['branch'], 50 | complaint_dict.data['course'], 51 | complaint_dict.data['year'], 52 | complaint_dict.data['type_of_lost_and_found'], 53 | complaint_dict.data['description'], 54 | complaint_dict.data['drive_link'] 55 | ]] 56 | } 57 | ).execute() 58 | return Response(complaint_dict.data, status=status.HTTP_201_CREATED) 59 | 60 | 61 | class LostAndFoundListView(GenericAPIView): 62 | """ 63 | get: 64 | Returns the list of all lost and found objects created by the authenticated user 65 | """ 66 | permission_classes = (permissions.IsAuthenticated,) 67 | # pylint: disable=no-member 68 | queryset = LostAndFound.objects.all() 69 | serializer_class = LostAndFoundListSerializer 70 | 71 | def get(self, request): 72 | serializer = self.get_serializer() 73 | list_lost_and_found = serializer.get_list() 74 | list_lost_and_found_dict = LostAndFoundSerializer( 75 | list_lost_and_found, many=True) 76 | return Response(list_lost_and_found_dict.data, status=status.HTTP_200_OK) 77 | -------------------------------------------------------------------------------- /workshop/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import ( 3 | ClubTagDeleteView, CouncilView, CouncilDetailView, ClubDetailView, ClubDetailWorkshopView, 4 | ClubTagsView, ClubSubscriptionToggleView, EntityDetailView, EntityDetailWorkshopView, 5 | EntityTagCreateView, EntityTagDeleteView, EntityTagSearchView, EntityTagsView, EntityView, 6 | ClubTagCreateView, ClubTagSearchView, WorkshopTagsUpdateView, EntitySubscriptionToggleView, 7 | WorkshopActiveAndPastView, WorkshopPastView, ClubWorkshopCreateView, WorkshopDetailView, 8 | WorkshopActiveView, WorkshopContactsUpdateView, WorkshopInterestedToggleView, 9 | WorkshopInterestedView, WorkshopSearchView, WorkshopDateSearchView, WorkshopResourceCreateView, 10 | WorkshopResourceView, EntityWorkshopCreateView, CouncilSubscribeView, CouncilUnsubscribeView) 11 | # from .views import * 12 | 13 | urlpatterns = [ 14 | path('councils/', CouncilView.as_view()), 15 | path('councils//', CouncilDetailView.as_view()), 16 | path('councils//subscribe/', CouncilSubscribeView.as_view()), 17 | path('councils//unsubscribe/', CouncilUnsubscribeView.as_view()), 18 | 19 | path('clubs//', ClubDetailView.as_view()), 20 | path('clubs//workshops/', ClubDetailWorkshopView.as_view()), 21 | path('clubs//tags/', ClubTagsView.as_view()), 22 | path('clubs//tags/create/', ClubTagCreateView.as_view()), 23 | path('clubs//tags/delete/', ClubTagDeleteView.as_view()), 24 | path('clubs//tags/search/', ClubTagSearchView.as_view()), 25 | path('clubs//toggle-subscribed/', ClubSubscriptionToggleView.as_view()), 26 | path('clubs//workshops/create/', ClubWorkshopCreateView.as_view()), 27 | 28 | path('workshops/', WorkshopActiveAndPastView.as_view()), 29 | path('workshops/active/', WorkshopActiveView.as_view()), 30 | path('workshops/past/', WorkshopPastView.as_view()), 31 | path('workshops//', WorkshopDetailView.as_view()), 32 | path('workshops//update-tags/', WorkshopTagsUpdateView.as_view()), 33 | path('workshops//update-contacts/', WorkshopContactsUpdateView.as_view()), 34 | path('workshops//toggle-interested/', WorkshopInterestedToggleView.as_view()), 35 | path('workshops//resources/', WorkshopResourceCreateView.as_view()), 36 | path('workshops/interested/', WorkshopInterestedView.as_view()), 37 | path('workshops/search/', WorkshopSearchView.as_view()), 38 | path('workshops/search/date/', WorkshopDateSearchView.as_view()), 39 | path('resources//', WorkshopResourceView.as_view()), 40 | 41 | path('entities/', EntityView.as_view()), 42 | path('entities//', EntityDetailView.as_view()), 43 | path('entities//tags/', EntityTagsView.as_view()), 44 | path('entities//tags/create/', EntityTagCreateView.as_view()), 45 | path('entities//tags/delete/', EntityTagDeleteView.as_view()), 46 | path('entities//tags/search/', EntityTagSearchView.as_view()), 47 | path('entities//toggle-subscribed/', EntitySubscriptionToggleView.as_view()), 48 | path('entities//workshops/', EntityDetailWorkshopView.as_view()), 49 | path('entities//workshops/create/', EntityWorkshopCreateView.as_view()), 50 | ] 51 | -------------------------------------------------------------------------------- /parliament_detail/serializers.py: -------------------------------------------------------------------------------- 1 | # from datetime import date 2 | from rest_framework import serializers 3 | from authentication.serializers import ProfileSerializer 4 | from authentication.models import UserProfile 5 | from .models import Contact, Update, Suggestion 6 | 7 | class ContactsSerializer(serializers.ModelSerializer): 8 | profile = serializers.SerializerMethodField() 9 | 10 | def get_profile(self,obj): 11 | serializer = ProfileSerializer(obj.profile) 12 | return serializer.data 13 | 14 | class Meta: 15 | model = Contact 16 | fields = ("id", "profile", "designation", "email", "phone") 17 | 18 | class ContactCreateSerializer(serializers.ModelSerializer): 19 | def save(self, **kwargs): 20 | data = self.validated_data 21 | # Can't create anothor contact if you already have one. 22 | if Contact.objects.filter(profile=data["profile"]).exists(): 23 | raise serializers.ValidationError("Contact already exists") 24 | contact = Contact.objects.create( 25 | designation=data['designation'], 26 | profile= data['profile'], 27 | ) 28 | contact.save() 29 | return contact 30 | 31 | class Meta: 32 | model = Contact 33 | fields = ("id", "profile", "designation", "email", "phone") 34 | 35 | class UpdateListSerializer(serializers.ModelSerializer): 36 | class Meta: 37 | #pylint: disable=no-member 38 | model = Update 39 | fields=("id","title","description","author","date","committee") 40 | 41 | class UpdateDetailSerializer(serializers.ModelSerializer): 42 | class Meta: 43 | model = Update 44 | read_only_fields = ("id","author") 45 | fields=("id","title","description","author","date","committee") 46 | 47 | class UpdateCreateSerializer(serializers.ModelSerializer): 48 | 49 | author=serializers.PrimaryKeyRelatedField(read_only=True) 50 | 51 | class Meta: 52 | #pylint: disable=no-member 53 | model = Update 54 | read_only_fields = ("id","author") 55 | fields=("id","title","description","author","date","committee") 56 | 57 | class SuggestionListSerializer(serializers.ModelSerializer): 58 | class Meta: 59 | #pylint: disable=no-member 60 | model = Suggestion 61 | fields=("id","title","date") 62 | 63 | class SuggestionDetailSerializer(serializers.ModelSerializer): 64 | has_voted = serializers.SerializerMethodField() 65 | 66 | def get_has_voted(self, obj): 67 | """Check if already voted""" 68 | # pylint: disable=no-member 69 | if(self.context['request'].user.is_authenticated): 70 | user = UserProfile.objects.get(user=self.context['request'].user) 71 | # if user in obj.voters.all(): 72 | if obj.voters.filter(id = user.id).exists(): 73 | return True 74 | return False 75 | 76 | 77 | class Meta: 78 | model = Suggestion 79 | read_only_fields = ("id","author","upvotes", "downvotes") 80 | fields=("id","title","description","author","date","upvotes","downvotes","has_voted") 81 | 82 | 83 | class SuggestionCreateSerializer(serializers.ModelSerializer): 84 | 85 | author=serializers.PrimaryKeyRelatedField(read_only=True) 86 | 87 | class Meta: 88 | #pylint: disable=no-member 89 | model = Suggestion 90 | read_only_fields = ("id","author","upvotes", "downvotes") 91 | fields=("id","title","description","author","date","upvotes", "downvotes") 92 | -------------------------------------------------------------------------------- /noticeboard/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics, permissions, status 2 | from rest_framework.response import Response 3 | 4 | from authentication.models import UserProfile 5 | from .models import NoticeBoard 6 | from .serializers import NoticeDetailSerializer, NoticeCreateSerializer, NoticeListSerializer 7 | from .permissions import AllowNoticeContact 8 | 9 | 10 | class NoticeListView(generics.ListAPIView): 11 | """ 12 | Get All Notices 13 | """ 14 | 15 | queryset = ( 16 | # pylint: disable=no-member 17 | NoticeBoard.objects.all() 18 | .order_by("-importance", "-date") 19 | ) 20 | permission_classes = (permissions.AllowAny,) 21 | serializer_class = NoticeListSerializer 22 | 23 | class NoticeCreateView(generics.CreateAPIView): 24 | """ 25 | Create New Notice 26 | """ 27 | # pylint: disable=no-member 28 | queryset = NoticeBoard.objects.all() 29 | permission_classes = (permissions.IsAuthenticated, AllowNoticeContact) 30 | serializer_class = NoticeCreateSerializer 31 | 32 | class NoticeDetailView(generics.RetrieveUpdateDestroyAPIView): 33 | """ 34 | Update and Delete a Notice 35 | """ 36 | 37 | permission_classes = (permissions.IsAuthenticated, AllowNoticeContact) 38 | serializer_class = NoticeDetailSerializer 39 | # pylint: disable=no-member 40 | queryset = NoticeBoard.objects.all() 41 | 42 | class NoticeUpvoteView(generics.GenericAPIView): 43 | """ 44 | Upvotes a notice 45 | """ 46 | # pylint: disable=no-member 47 | queryset = NoticeBoard.objects.all() 48 | permission_classes = (permissions.IsAuthenticated,) 49 | serializer_class = NoticeDetailSerializer 50 | 51 | def get(self, request, pk): 52 | """Check if already voted or not""" 53 | notice = self.queryset.get(id=pk) 54 | user = UserProfile.objects.get(user=request.user) 55 | if notice is not None: 56 | if notice.voters.filter(id = user.id).exists(): 57 | return Response( 58 | {"Error": "You can vote only once"}, status=status.HTTP_208_ALREADY_REPORTED 59 | ) 60 | notice.upvotes += 1 61 | notice.voters.add(user) 62 | notice.save() 63 | return Response( 64 | {"Message": "Upvoted successfully"}, status=status.HTTP_200_OK 65 | ) 66 | return Response( 67 | {"Error": "Notice not found"}, status=status.HTTP_204_NO_CONTENT 68 | ) 69 | 70 | 71 | class NoticeDownvoteView(generics.GenericAPIView): 72 | """ 73 | Downvote a notice 74 | """ 75 | # pylint: disable=no-member 76 | queryset = NoticeBoard.objects.all() 77 | permission_classes = (permissions.IsAuthenticated,) 78 | serializer_class = NoticeDetailSerializer 79 | 80 | def get(self, request, pk): 81 | """Check if already voted or not""" 82 | notice = self.queryset.get(id=pk) 83 | user = UserProfile.objects.get(user=request.user) 84 | if notice is not None: 85 | if notice.voters.filter(id = user.id).exists(): 86 | return Response( 87 | {"Error": "You can vote only once"}, status=status.HTTP_208_ALREADY_REPORTED 88 | ) 89 | notice.downvotes += 1 90 | notice.voters.add(user) 91 | notice.save() 92 | return Response( 93 | {"Message": "Downvoted successfully"}, status=status.HTTP_200_OK 94 | ) 95 | return Response( 96 | {"Error": "Notice not found"}, status=status.HTTP_204_NO_CONTENT 97 | ) 98 | -------------------------------------------------------------------------------- /grievance/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import status, permissions 2 | from rest_framework.response import Response 3 | from rest_framework.generics import GenericAPIView 4 | from .models import Complaint 5 | from .serializers import ( 6 | CreateGrievanceSerializer, CountGrievanceSerializer, 7 | GrievanceSerializer, GrievanceDetailSerializer) 8 | from googleapiclient.discovery import build 9 | from google.oauth2 import service_account 10 | 11 | SCOPES = ['https://www.googleapis.com/auth/spreadsheets'] 12 | SERVICE_ACCOUNT_FILE = 'keys.json' 13 | 14 | cred = None 15 | cred = service_account.Credentials.from_service_account_file( 16 | SERVICE_ACCOUNT_FILE, scopes=SCOPES) 17 | 18 | GRIEVANCE_SPREADSHEET_ID = '1Hch-gohmuAeAeJFwaozb1xz_Oj7DLa6C0qOhAuk3t-o' 19 | 20 | 21 | class CreateGrievanceView(GenericAPIView): 22 | """ 23 | post: 24 | Creates a new grievance object and returns the 25 | Id, Name, Branch, Course, Year, Type, Description, Drive Link and Status of the object. 26 | """ 27 | permission_classes = (permissions.IsAuthenticated,) 28 | # pylint: disable=no-member 29 | queryset = Complaint.objects.all() 30 | serializer_class = CreateGrievanceSerializer 31 | 32 | def post(self, request, *args, **kwargs): 33 | serializer = self.get_serializer(data=request.data) 34 | serializer.is_valid(raise_exception=True) 35 | complaint = serializer.save() 36 | complaint_dict = GrievanceSerializer(complaint) 37 | service = build('sheets', 'v4', credentials=cred) 38 | sheet = service.spreadsheets() 39 | sheet.values().append( 40 | spreadsheetId=GRIEVANCE_SPREADSHEET_ID, 41 | range="grievance!A1:I1", 42 | valueInputOption="USER_ENTERED", 43 | insertDataOption="INSERT_ROWS", 44 | body={ 45 | "values": [[ 46 | complaint_dict.data['id'], 47 | complaint_dict.data['name'], 48 | complaint_dict.data['branch'], 49 | complaint_dict.data['course'], 50 | complaint_dict.data['year'], 51 | complaint_dict.data['type_of_complaint'], 52 | complaint_dict.data['description'], 53 | complaint_dict.data['drive_link'], 54 | "Pending" 55 | ]] 56 | } 57 | ).execute() 58 | return Response(complaint_dict.data, status=status.HTTP_201_CREATED) 59 | 60 | 61 | class CountGrievanceView(GenericAPIView): 62 | """ 63 | get: 64 | Returns a dictionary consisting of number of closed, registered and pending grievances. 65 | """ 66 | permission_classes = (permissions.IsAuthenticated,) 67 | # pylint: disable=no-member 68 | queryset = Complaint.objects.all() 69 | serializer_class = CountGrievanceSerializer 70 | 71 | def get(self, request, *args, **kwargs): 72 | serializer = self.get_serializer() 73 | count = serializer.get_count() 74 | return Response(count, status=status.HTTP_200_OK) 75 | 76 | 77 | class GrievanceDetailView(GenericAPIView): 78 | """ 79 | get: 80 | Returns the list of all grievances created by the authenticated user 81 | having the given status value 'st'. 82 | """ 83 | permission_classes = (permissions.IsAuthenticated,) 84 | # pylint: disable=no-member 85 | queryset = Complaint.objects.all() 86 | serializer_class = GrievanceDetailSerializer 87 | 88 | def get(self, request, st): 89 | serializer = self.get_serializer() 90 | detailed_complaints = serializer.get_details(status=st) 91 | detailed_complaints_dict = GrievanceSerializer(detailed_complaints, many=True) 92 | return Response(detailed_complaints_dict.data, status=status.HTTP_200_OK) 93 | -------------------------------------------------------------------------------- /grievance/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import Complaint 3 | 4 | 5 | class CreateGrievanceSerializer(serializers.Serializer): 6 | TYPE = (('Security', "Security"), ('Health&Hygiene', "Health&Hygiene"), 7 | ('HostelMess', "HostelMess"), ('Academics', "Academics"), 8 | ('Council', "Council"), ('Others', "Others")) 9 | YEAR = (('1st', "1st"), ('2nd', "2nd"), 10 | ('3rd', "3rd"), ('4th', "4th"), ('5th', "5th")) 11 | COURSE = (('B.Tech', "B.Tech"), ('IDD', "IDD"), ('M.Tech', "M.Tech")) 12 | BRANCH = (('Architecture', "Architecture"), ('Ceramic', "Ceramic"), 13 | ('Chemical', "Chemical"), ('Civil', "Civil"), ('Computer Science', "Computer Science"), 14 | ('Electrical',"Electrical"), ('Electronics', "Electronics"), ('Mechanical', "Mechanical"), 15 | ('Metallurgical', "Metallurgical"), ('Mining', "Mining"), ('Pharmaceutical', "Pharmaceutical")) 16 | 17 | name = serializers.CharField(max_length=200) 18 | branch = serializers.ChoiceField(choices=BRANCH) 19 | course = serializers.ChoiceField(choices=COURSE) 20 | year = serializers.ChoiceField(choices=YEAR) 21 | type_of_complaint = serializers.ChoiceField(choices=TYPE) 22 | description = serializers.CharField(max_length=4000) 23 | drive_link = serializers.URLField( 24 | max_length=400, allow_blank=True, required=False) 25 | 26 | def save(self): 27 | """ 28 | Takes the validated data, creates a new grievance object and returns it. 29 | """ 30 | name = self.validated_data.get('name') 31 | branch = self.validated_data.get('branch') 32 | course = self.validated_data.get('course') 33 | year = self.validated_data.get('year') 34 | type_of_complaint = self.validated_data.get('type_of_complaint') 35 | description = self.validated_data.get('description') 36 | drive_link = self.validated_data.get('drive_link', '') 37 | user = self.context["request"].user 38 | 39 | # pylint: disable=no-member 40 | complaint = Complaint.objects.create( 41 | user=user, name=name, branch=branch, course=course, 42 | year=year, type_of_complaint=type_of_complaint, 43 | description=description, drive_link=drive_link) 44 | complaint.save() 45 | return complaint 46 | 47 | 48 | class CountGrievanceSerializer(serializers.Serializer): 49 | def get_count(self): 50 | """ 51 | Returns the count of closed, registered and pending grievances. 52 | """ 53 | user = self.context["request"].user 54 | # pylint: disable=no-member 55 | user_complaints = Complaint.objects.filter(user=user) 56 | closed_complaints = user_complaints.filter(status=1) 57 | registered_complaints = user_complaints.filter(status=2) 58 | pending_complaints = user_complaints.filter(status=3) 59 | 60 | return { 61 | "closed": closed_complaints.count(), 62 | "registered": registered_complaints.count(), 63 | "pending": pending_complaints.count() 64 | } 65 | 66 | 67 | class GrievanceDetailSerializer(serializers.Serializer): 68 | STATUS = ((1, 'Closed'), (2, 'Registered'), (3, 'Pending')) 69 | 70 | def get_details(self, status): 71 | """ 72 | Returns an array consisting of grievances created by the user 73 | having status same as the given status. 74 | """ 75 | user = self.context["request"].user 76 | # pylint: disable=no-member 77 | user_complaints = Complaint.objects.filter(user=user) 78 | detailed_complaints = user_complaints.filter(status=status).all() 79 | return detailed_complaints 80 | 81 | 82 | class GrievanceSerializer(serializers.ModelSerializer): 83 | class Meta: 84 | model = Complaint 85 | fields = ('id', 'name', 'branch', 'course', 'year', 'type_of_complaint', 86 | 'description', 'drive_link', 'status') 87 | -------------------------------------------------------------------------------- /workshop/migrations/0021_entity_event_eventresource.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.10 on 2020-11-20 06:30 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('authentication', '0012_auto_20200303_2140'), 11 | ('workshop', '0020_auto_20200503_1950'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Entity', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('name', models.CharField(max_length=50)), 20 | ('description', models.TextField(blank=True, null=True)), 21 | ('small_image_url', models.URLField(blank=True, null=True)), 22 | ('large_image_url', models.URLField(blank=True, null=True)), 23 | ('website_url', models.URLField(blank=True, null=True)), 24 | ('facebook_url', models.URLField(blank=True, null=True)), 25 | ('twitter_url', models.URLField(blank=True, null=True)), 26 | ('instagram_url', models.URLField(blank=True, null=True)), 27 | ('linkedin_url', models.URLField(blank=True, null=True)), 28 | ('youtube_url', models.URLField(blank=True, null=True)), 29 | ('joint_secy', models.ManyToManyField(blank=True, related_name='entity_joint_secy', to='authentication.UserProfile', verbose_name='Joint Secretary')), 30 | ('secy', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='entity_secy', to='authentication.UserProfile', verbose_name='Secretary')), 31 | ('subscribed_users', models.ManyToManyField(blank=True, related_name='entity_subscriptions', to='authentication.UserProfile')), 32 | ], 33 | ), 34 | migrations.CreateModel( 35 | name='Event', 36 | fields=[ 37 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 38 | ('title', models.CharField(max_length=50)), 39 | ('description', models.TextField(blank=True, null=True)), 40 | ('date', models.DateField()), 41 | ('time', models.TimeField(blank=True, null=True)), 42 | ('location', models.CharField(blank=True, max_length=50)), 43 | ('latitude', models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True)), 44 | ('longitude', models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True)), 45 | ('audience', models.CharField(blank=True, max_length=50)), 46 | ('image_url', models.URLField(blank=True, null=True)), 47 | ('link', models.URLField(blank=True, null=True)), 48 | ('contacts', models.ManyToManyField(blank=True, related_name='organized_events', to='authentication.UserProfile')), 49 | ('entity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='workshop.Entity')), 50 | ('interested_users', models.ManyToManyField(blank=True, related_name='interested_events', to='authentication.UserProfile')), 51 | ('tags', models.ManyToManyField(blank=True, related_name='tagged_events', to='workshop.Tag')), 52 | ], 53 | ), 54 | migrations.CreateModel( 55 | name='EventResource', 56 | fields=[ 57 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 58 | ('name', models.CharField(max_length=50)), 59 | ('link', models.URLField()), 60 | ('resource_type', models.CharField(choices=[('Prerequisite', 'Prerequisite'), ('Material', 'Material')], max_length=20)), 61 | ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='resources', to='workshop.Event')), 62 | ], 63 | ), 64 | ] 65 | -------------------------------------------------------------------------------- /workshop/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Council, Club, Tag, WorkshopResource, Workshop, Entity 3 | 4 | @admin.register(Council) 5 | class CouncilAdmin(admin.ModelAdmin): 6 | def get_gensec(self, obj): 7 | """ 8 | Get the General Secretary of a Council 9 | """ 10 | if obj.gensec is None: 11 | return None 12 | return obj.gensec.name 13 | 14 | def get_joint_gensec(self, obj): 15 | """ 16 | Get the Joint General Secretary of a Council 17 | """ 18 | return ',\n'.join([o.name for o in obj.joint_gensec.all()]) 19 | 20 | def get_queryset(self, request): 21 | return super().get_queryset(request) \ 22 | .select_related('gensec').prefetch_related('joint_gensec') 23 | 24 | list_display = ('__str__', 'name', 'get_gensec', 'get_joint_gensec',) 25 | search_fields = ('name', 'gensec__name', 'joint_gensec__name',) 26 | 27 | get_gensec.short_description = 'General Secretary' 28 | get_joint_gensec.short_description = 'Joint General Secretary' 29 | 30 | 31 | @admin.register(Club) 32 | class ClubAdmin(admin.ModelAdmin): 33 | def get_secy(self, obj): 34 | """ 35 | Get the Secretary of a Club 36 | """ 37 | if obj.secy is None: 38 | return None 39 | return obj.secy.name 40 | 41 | def get_joint_secy(self, obj): 42 | """ 43 | Get the Joint Secretary of a Club 44 | """ 45 | return ',\n'.join([o.name for o in obj.joint_secy.all()]) 46 | 47 | def get_subscribed_users(self, obj): 48 | """ 49 | Get the count of subscribed users for a Club 50 | """ 51 | return obj.subscribed_users.count() 52 | 53 | def get_queryset(self, request): 54 | return super().get_queryset(request) \ 55 | .select_related('council', 'secy').prefetch_related('joint_secy', 'subscribed_users') 56 | 57 | list_display = ( 58 | '__str__', 'name', 'council', 'get_secy', 'get_joint_secy', 'get_subscribed_users') 59 | search_fields = ('name', 'secy__name', 'joint_secy__name',) 60 | list_filter = ('council',) 61 | 62 | get_secy.short_description = 'Secretary' 63 | get_joint_secy.short_description = 'Joint Secretary' 64 | get_subscribed_users.short_description = 'Subscribed Users' 65 | 66 | 67 | @admin.register(Entity) 68 | class EntityAdmin(admin.ModelAdmin): 69 | def get_point_of_contact(self, obj): 70 | """ 71 | Get the Point of Contact of an Entity 72 | """ 73 | return ',\n'.join([o.name for o in obj.point_of_contact.all()]) 74 | 75 | def get_subscribed_users(self, obj): 76 | """ 77 | Get the count of subscribed users for an Entity 78 | """ 79 | return obj.subscribed_users.count() 80 | 81 | def get_queryset(self, request): 82 | return super().get_queryset(request) \ 83 | .prefetch_related('point_of_contact', 'subscribed_users') 84 | 85 | list_display = ( 86 | '__str__', 'name', 'get_point_of_contact', 'get_subscribed_users') 87 | search_fields = ('name', 'point_of_contact__name',) 88 | 89 | get_point_of_contact.short_description = 'Point of Contact' 90 | get_subscribed_users.short_description = 'Subscribed Users' 91 | 92 | 93 | @admin.register(Tag) 94 | class TagAdmin(admin.ModelAdmin): 95 | list_display = ('tag_name', 'club', 'entity') 96 | search_fields = ('tag_name',) 97 | list_filter = ('club', 'entity',) 98 | 99 | def get_queryset(self, request): 100 | return super().get_queryset(request).select_related('club', 'entity') 101 | 102 | 103 | @admin.register(WorkshopResource) 104 | class WorkshopResourceAdmin(admin.ModelAdmin): 105 | list_display = ('name', 'link', 'workshop', 'resource_type') 106 | search_fields = ('name',) 107 | list_filter = ('resource_type',) 108 | 109 | 110 | @admin.register(Workshop) 111 | class WorkshopAdmin(admin.ModelAdmin): 112 | def get_contacts(self, obj): 113 | """ 114 | Get the contacts for a workshop 115 | """ 116 | return ',\n'.join([o.name for o in obj.contacts.all()]) 117 | 118 | def get_tags(self, obj): 119 | """ 120 | Get the tags for a workshop 121 | """ 122 | return ',\n'.join([o.tag_name for o in obj.tags.all()]) 123 | 124 | def get_interested_users(self, obj): 125 | """ 126 | Get the count of interested users for a workshop 127 | """ 128 | return obj.interested_users.count() 129 | 130 | def get_queryset(self, request): 131 | return super().get_queryset(request) \ 132 | .select_related('club').prefetch_related('interested_users', 'contacts', 'tags') 133 | 134 | list_display = ( 135 | '__str__', 'title', 'club', 'date', 'time', 'is_workshop', 136 | 'get_interested_users', 'get_contacts', 'get_tags') 137 | search_fields = ('title', 'contacts__name', 'tags__tag_name') 138 | list_filter = ('club',) 139 | 140 | get_interested_users.short_description = 'Interested Users' 141 | get_contacts.short_description = 'Contacts' 142 | get_tags.short_description = 'Tags' 143 | -------------------------------------------------------------------------------- /workshops/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for workshops project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.2.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.2/ref/settings/ 11 | """ 12 | 13 | import os 14 | import django_heroku 15 | import firebase_admin 16 | import pyAesCrypt 17 | from firebase_admin import credentials 18 | from decouple import config 19 | 20 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 21 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 22 | 23 | 24 | # Quick-start development settings - unsuitable for production 25 | # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ 26 | 27 | # SECURITY WARNING: don't run with debug turned on in production! 28 | DEBUG = int(os.environ.get('DEBUG', '1')) 29 | 30 | # SECURITY WARNING: keep the secret key used in production secret! 31 | if DEBUG: 32 | SECRET_KEY = '1ehe!ow4lk7v!5nnl0xt(t$zxi5v*m3_^q%dx3du$4g7nee%m5' 33 | else: 34 | SECRET_KEY = config('SECRET_KEY') 35 | 36 | 37 | ALLOWED_HOSTS = ['*'] 38 | 39 | 40 | # Application definition 41 | 42 | INSTALLED_APPS = [ 43 | 'django.contrib.admin', 44 | 'django.contrib.auth', 45 | 'django.contrib.contenttypes', 46 | 'django.contrib.sessions', 47 | 'django.contrib.messages', 48 | 'django.contrib.staticfiles', 49 | 'rest_framework', 50 | 'rest_framework.authtoken', 51 | 'drf_yasg2', 52 | 'corsheaders', 53 | 'authentication', 54 | 'academics', 55 | 'workshop', 56 | 'team', 57 | 'noticeboard', 58 | 'grievance', 59 | 'parliament_detail', 60 | 'config', 61 | 'lost_and_found', 62 | 'mess' 63 | ] 64 | 65 | MIDDLEWARE = [ 66 | 'corsheaders.middleware.CorsMiddleware', 67 | 'django.middleware.security.SecurityMiddleware', 68 | 'django.contrib.sessions.middleware.SessionMiddleware', 69 | 'django.middleware.common.CommonMiddleware', 70 | 'django.middleware.csrf.CsrfViewMiddleware', 71 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 72 | 'django.contrib.messages.middleware.MessageMiddleware', 73 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 74 | ] 75 | 76 | ROOT_URLCONF = 'workshops.urls' 77 | 78 | TEMPLATES = [ 79 | { 80 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 81 | 'DIRS': [], 82 | 'APP_DIRS': True, 83 | 'OPTIONS': { 84 | 'context_processors': [ 85 | 'django.template.context_processors.debug', 86 | 'django.template.context_processors.request', 87 | 'django.contrib.auth.context_processors.auth', 88 | 'django.contrib.messages.context_processors.messages', 89 | ], 90 | }, 91 | }, 92 | ] 93 | 94 | WSGI_APPLICATION = 'workshops.wsgi.application' 95 | 96 | CORS_ORIGIN_ALLOW_ALL = True 97 | 98 | 99 | REST_FRAMEWORK = { 100 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 101 | 'rest_framework.authentication.TokenAuthentication', 102 | # 'rest_framework.authentication.BasicAuthentication', 103 | ) 104 | } 105 | 106 | SWAGGER_SETTINGS = { 107 | 'SECURITY_DEFINITIONS': { 108 | 'Token': { 109 | 'type': 'apiKey', 110 | 'name': 'Authorization', 111 | 'in': 'header' 112 | } 113 | } 114 | } 115 | 116 | 117 | # Database 118 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases 119 | 120 | DATABASES = { 121 | 'default': { 122 | 'ENGINE': 'django.db.backends.sqlite3', 123 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 124 | } 125 | } 126 | 127 | 128 | # Password validation 129 | # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators 130 | 131 | AUTH_PASSWORD_VALIDATORS = [ 132 | { 133 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 134 | }, 135 | { 136 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 137 | }, 138 | { 139 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 140 | }, 141 | { 142 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 143 | }, 144 | ] 145 | 146 | 147 | # Internationalization 148 | # https://docs.djangoproject.com/en/2.2/topics/i18n/ 149 | 150 | LANGUAGE_CODE = 'en-us' 151 | 152 | TIME_ZONE = 'Asia/Kolkata' 153 | 154 | USE_I18N = True 155 | 156 | USE_L10N = True 157 | 158 | USE_TZ = True 159 | 160 | 161 | # Static files (CSS, JavaScript, Images) 162 | # https://docs.djangoproject.com/en/2.2/howto/static-files/ 163 | 164 | STATIC_URL = '/static/' 165 | 166 | # Activate Django-Heroku. 167 | django_heroku.settings(locals()) 168 | 169 | # Firebase Credentials 170 | # if not DEBUG: 171 | with open("service_account.json.aes", "rb") as encrypted_file: 172 | with open("service_account.json", "wb") as decrypted_file: 173 | # decrypt file stream 174 | pyAesCrypt.decryptStream( 175 | encrypted_file, 176 | decrypted_file, 177 | config('SERVICE_ACCOUNT_DECRYPT_KEY'), 178 | 64*1024, 179 | int(config('SERVICE_ACCOUNT_ENC_SIZE')) 180 | ) 181 | 182 | cred = credentials.Certificate(os.path.join(BASE_DIR, 'service_account.json')) 183 | default_app = firebase_admin.initialize_app(cred) 184 | 185 | LOGGING = { 186 | 'version': 1, 187 | 'disable_existing_loggers': False, 188 | 'handlers': { 189 | 'console': { 190 | 'class': 'logging.StreamHandler', 191 | }, 192 | }, 193 | 'root': { 194 | 'handlers': ['console'], 195 | 'level': 'WARNING', 196 | }, 197 | 'loggers': { 198 | 'django': { 199 | 'handlers': ['console'], 200 | 'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'), 201 | 'propagate': False, 202 | }, 203 | }, 204 | } 205 | -------------------------------------------------------------------------------- /academics/migrations/0001_added_academic_section.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.13 on 2021-12-11 20:49 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | replaces = [('academics', '0001_initial'), ('academics', '0002_auto_20211206_2130'), ('academics', '0003_auto_20211210_1744'), 9 | ('academics', '0004_auto_20211211_2054'), ('academics', '0005_auto_20211211_2057'), ('academics', '0006_auto_20211211_2108')] 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='ProffsAndHODs', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, 21 | primary_key=True, serialize=False, verbose_name='ID')), 22 | ('department', models.CharField(max_length=60)), 23 | ('year_of_joining', models.CharField(max_length=10)), 24 | ], 25 | ), 26 | migrations.CreateModel( 27 | name='AcademicSchedule', 28 | fields=[ 29 | ('id', models.AutoField(auto_created=True, 30 | primary_key=True, serialize=False, verbose_name='ID')), 31 | ('department', models.CharField(choices=[('bce', 'Biochemical Engineering'), ('bme', 'Biomedical Engineering'), ('cer', 'Ceramic Engineering'), ('che', 'Chemical Engineering'), ('chy', 'Chemistry'), ('civ', 'Civil Engineering'), ('cse', 'Computer Science and Engineering'), ('ece', 'Electronics Engineering'), ( 32 | 'eee', 'Electrical Engineering'), ('mat', 'Mathematics and Computing'), ('mec', 'Mechanical Engineering'), ('met', 'Metallurgical Engineering'), ('min', 'Mining Engineering'), ('mst', 'Materials Science and Technology'), ('phe', 'Pharmaceutical Engineering and Technology'), ('phy', 'Physics'), ('hss', 'Humanistic Studies')], max_length=60)), 33 | ('year_of_joining', models.CharField(max_length=10)), 34 | ('schedule_url', models.URLField()), 35 | ], 36 | ), 37 | migrations.AlterModelTable( 38 | name='proffsandhods', 39 | table='Proffs and HODs', 40 | ), 41 | migrations.AlterModelOptions( 42 | name='proffsandhods', 43 | options={'verbose_name': 'Proffs and HODs', 44 | 'verbose_name_plural': 'Proffs and HODs'}, 45 | ), 46 | migrations.RemoveField( 47 | model_name='proffsandhods', 48 | name='year_of_joining', 49 | ), 50 | migrations.AddField( 51 | model_name='proffsandhods', 52 | name='proffs_and_HODs', 53 | field=models.URLField(default='https://www.iitbhu.ac.in/dept'), 54 | ), 55 | migrations.AlterModelTable( 56 | name='proffsandhods', 57 | table=None, 58 | ), 59 | migrations.RenameModel( 60 | old_name='ProffsAndHODs', 61 | new_name='ProfsAndHODs', 62 | ), 63 | migrations.AlterModelOptions( 64 | name='profsandhods', 65 | options={'verbose_name': 'Profs and HODs', 66 | 'verbose_name_plural': 'Profs and HODs'}, 67 | ), 68 | migrations.RenameField( 69 | model_name='profsandhods', 70 | old_name='proffs_and_HODs', 71 | new_name='profs_and_HODs', 72 | ), 73 | migrations.CreateModel( 74 | name='StudyMaterials', 75 | fields=[ 76 | ('id', models.AutoField(auto_created=True, 77 | primary_key=True, serialize=False, verbose_name='ID')), 78 | ('resource_url', models.URLField()), 79 | ('department', models.CharField(choices=[('bce', 'Biochemical Engineering'), ('bme', 'Biomedical Engineering'), ('cer', 'Ceramic Engineering'), ('che', 'Chemical Engineering'), ('chy', 'Chemistry'), ('civ', 'Civil Engineering'), ('cse', 'Computer Science and Engineering'), ('ece', 'Electronics Engineering'), ('eee', 'Electrical Engineering'), ( 80 | 'mat', 'Mathematics and Computing'), ('mec', 'Mechanical Engineering'), ('met', 'Metallurgical Engineering'), ('min', 'Mining Engineering'), ('mst', 'Materials Science and Technology'), ('phe', 'Pharmaceutical Engineering and Technology'), ('phy', 'Physics'), ('hss', 'Humanistic Studies')], default='cse', max_length=60)), 81 | ], 82 | options={ 83 | 'verbose_name_plural': 'Study Materials', 84 | }, 85 | ), 86 | migrations.AlterField( 87 | model_name='profsandhods', 88 | name='department', 89 | field=models.CharField(choices=[('bce', 'Biochemical Engineering'), ('bme', 'Biomedical Engineering'), ('cer', 'Ceramic Engineering'), ('che', 'Chemical Engineering'), ('chy', 'Chemistry'), ('civ', 'Civil Engineering'), ('cse', 'Computer Science and Engineering'), ('ece', 'Electronics Engineering'), ('eee', 'Electrical Engineering'), ( 90 | 'mat', 'Mathematics and Computing'), ('mec', 'Mechanical Engineering'), ('met', 'Metallurgical Engineering'), ('min', 'Mining Engineering'), ('mst', 'Materials Science and Technology'), ('phe', 'Pharmaceutical Engineering and Technology'), ('phy', 'Physics'), ('hss', 'Humanistic Studies')], max_length=60), 91 | ), 92 | migrations.AlterField( 93 | model_name='profsandhods', 94 | name='department', 95 | field=models.CharField(max_length=60), 96 | ), 97 | migrations.AlterField( 98 | model_name='studymaterials', 99 | name='department', 100 | field=models.CharField(choices=[('bce', 'Biochemical Engineering'), ('bme', 'Biomedical Engineering'), ('cer', 'Ceramic Engineering'), ('che', 'Chemical Engineering'), ('chy', 'Chemistry'), ('civ', 'Civil Engineering'), ('cse', 'Computer Science and Engineering'), ('ece', 'Electronics Engineering'), ('eee', 'Electrical Engineering'), ( 101 | 'mat', 'Mathematics and Computing'), ('mec', 'Mechanical Engineering'), ('met', 'Metallurgical Engineering'), ('min', 'Mining Engineering'), ('mst', 'Materials Science and Technology'), ('phe', 'Pharmaceutical Engineering and Technology'), ('phy', 'Physics'), ('hss', 'Humanistic Studies')], max_length=60), 102 | ), 103 | ] 104 | -------------------------------------------------------------------------------- /authentication/utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from firebase_admin import auth, messaging, exceptions 3 | from rest_framework.status import HTTP_422_UNPROCESSABLE_ENTITY 4 | from rest_framework.exceptions import ValidationError 5 | from google.auth.exceptions import TransportError 6 | 7 | logger = logging.getLogger('django') 8 | 9 | class Student: 10 | 11 | dept_list = { 12 | 'bce': 'Biochemical Engineering', 13 | 'bme': 'Biomedical Engineering', 14 | 'cer': 'Ceramic Engineering', 15 | 'che': 'Chemical Engineering', 16 | 'chy': 'Chemistry', 17 | 'civ': 'Civil Engineering', 18 | 'cse': 'Computer Science and Engineering', 19 | 'ece': 'Electronics Engineering', 20 | 'eee': 'Electrical Engineering', 21 | 'mat': 'Mathematics and Computing', 22 | 'mec': 'Mechanical Engineering', 23 | 'met': 'Metallurgical Engineering', 24 | 'min': 'Mining Engineering', 25 | 'mst': 'Materials Science and Technology', 26 | 'phe': 'Pharmaceutical Engineering and Technology', 27 | 'phy': 'Physics', 28 | 'hss': 'Humanistic Studies' 29 | } 30 | 31 | @classmethod 32 | def get_department_code(cls, email): 33 | """ 34 | Get department code from email id 35 | """ 36 | username = email.split('@')[0] 37 | dept_code = username.split('.')[-1][:3] 38 | return dept_code 39 | 40 | @classmethod 41 | def get_department(cls, email): 42 | """ 43 | Get department name from email id 44 | """ 45 | dept_code = cls.get_department_code(email) 46 | return cls.dept_list[dept_code] 47 | 48 | @classmethod 49 | def get_year(cls, email): 50 | """ 51 | Get year from email id 52 | """ 53 | username = email.split('@')[0] 54 | year = username.split('.')[-1][3:] 55 | return '20' + year 56 | 57 | @classmethod 58 | def verify_email(cls, email): 59 | """ 60 | Verify institute email 61 | """ 62 | username = email.split('@')[0] 63 | domain = email.split('@')[1] 64 | if domain not in ['itbhu.ac.in', ]: 65 | return False 66 | if '.' not in username: 67 | return False 68 | dept_code = cls.get_department_code(email) 69 | if dept_code not in cls.dept_list: 70 | return False 71 | return True 72 | 73 | 74 | class FirebaseAPI: 75 | 76 | @classmethod 77 | def verify_id_token(cls, id_token): 78 | """ 79 | Verify the id token from firebase 80 | """ 81 | try: 82 | decoded_token = auth.verify_id_token(id_token) 83 | return decoded_token 84 | except ValueError as e: 85 | raise ValidationError( 86 | 'Invalid Firebase ID Token.', HTTP_422_UNPROCESSABLE_ENTITY) from e 87 | 88 | @classmethod 89 | def delete_user_by_uid(cls, uid): 90 | """ 91 | Delete User 92 | """ 93 | auth.delete_user(uid) 94 | 95 | @classmethod 96 | def get_photo_url(cls, uid): 97 | """ 98 | Get the photo url of the corresponding user 99 | """ 100 | # pylint: disable=protected-access 101 | return auth.get_user(uid)._data['photoUrl'] 102 | 103 | @classmethod 104 | def send_club_message(cls, data, club): 105 | """ 106 | Gets the message content for Clubs 107 | """ 108 | topic='C_'+str(club.id) 109 | if data.get('is_workshop', True): 110 | msg_notification=messaging.Notification( 111 | title="New Workshop in "+str(club.name), 112 | body=data['title']+" on "+str(data['date'].strftime('%d-%m-%Y')), 113 | image=data.get('image_url','')) 114 | else: 115 | msg_notification=messaging.Notification( 116 | title="New Event in "+str(club.name), 117 | body=data['title']+" on "+str(data['date'].strftime('%d-%m-%Y')), 118 | image=data.get('image_url','')) 119 | message = messaging.Message( 120 | notification=msg_notification, 121 | topic=topic 122 | ) 123 | 124 | try: 125 | response = messaging.send(message) 126 | logger.info('[Topic %s] Successfully sent message: %s', topic, response) 127 | except (exceptions.FirebaseError, TransportError) as e: 128 | logger.warning('[Topic %s] Could not send notification!', topic) 129 | logger.error(e) 130 | 131 | @classmethod 132 | def send_entity_message(cls, data, entity): 133 | """ 134 | Gets the message content for Entities 135 | """ 136 | topic = 'E_'+str(entity.id) 137 | if data.get('is_workshop', True): 138 | msg_notification=messaging.Notification( 139 | title="New Workshop in "+str(entity.name), 140 | body=data['title']+" on "+str(data['date'].strftime('%d-%m-%Y')), 141 | image=data.get('image_url','')) 142 | else: 143 | msg_notification=messaging.Notification( 144 | title="New Event in "+str(entity.name), 145 | body=data['title']+" on "+str(data['date'].strftime('%d-%m-%Y')), 146 | image=data.get('image_url','')) 147 | message = messaging.Message( 148 | notification=msg_notification, 149 | topic=topic 150 | ) 151 | try: 152 | response = messaging.send(message) 153 | logger.info('[Topic %s] Successfully sent message: %s', topic, response) 154 | except (exceptions.FirebaseError, TransportError) as e: 155 | logger.warning('[Topic %s] Could not send notification!', topic) 156 | logger.error(e) 157 | 158 | @classmethod 159 | def send_workshop_update(cls, instance, data): 160 | """ 161 | Gets the message content on updating workshop or event 162 | """ 163 | topic = 'W_' + str(instance.id) 164 | msg_notification = messaging.Notification( 165 | title=data['title']+" has been updated", 166 | body='Click here, Don\'t miss any detail', 167 | image=data.get('image_url','')) 168 | message = messaging.Message( 169 | notification=msg_notification, 170 | topic=topic 171 | ) 172 | try: 173 | response = messaging.send(message) 174 | logger.info('[Topic %s] Successfully sent message: %s', topic, response) 175 | except (exceptions.FirebaseError, TransportError) as e: 176 | logger.warning('[Topic %s] Could not send notification!', topic) 177 | logger.error(e) 178 | -------------------------------------------------------------------------------- /authentication/serializers.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=too-few-public-methods 2 | import logging 3 | from django.core.validators import RegexValidator 4 | from django.contrib.auth import get_user_model 5 | from rest_framework import serializers 6 | from drf_yasg2.utils import swagger_serializer_method 7 | from workshop.serializers import ClubSerializer, EntitySerializer 8 | from .utils import Student, FirebaseAPI 9 | from .models import UserProfile 10 | 11 | logger = logging.getLogger('django') 12 | 13 | phone_regex = RegexValidator( 14 | regex=r'^\+\d{9,15}$', 15 | message="Phone number must be entered in the format: '+919876543210'." 16 | ) 17 | 18 | 19 | class ResponseSerializer(serializers.Serializer): 20 | token = serializers.CharField(max_length=500) 21 | 22 | 23 | class LoginSerializer(serializers.Serializer): 24 | id_token = serializers.CharField(max_length=2400) 25 | 26 | def access_token_validate(self, access_token): 27 | """ 28 | Validate the firebase access token. 29 | """ 30 | try: 31 | return FirebaseAPI.verify_id_token(access_token) 32 | except serializers.ValidationError as e: 33 | raise serializers.ValidationError( 34 | "Invalid Firebase token!") from e 35 | 36 | def validate(self, attrs): 37 | id_token = attrs.get('id_token', None) 38 | current_user = None 39 | jwt = self.access_token_validate(id_token) 40 | uid = jwt['uid'] 41 | # pylint: disable=no-member 42 | profile = UserProfile.objects.filter(uid=uid) 43 | 44 | if profile: 45 | current_user = profile[0].user 46 | else: 47 | email = jwt['email'] 48 | if not Student.verify_email(email): 49 | raise serializers.ValidationError( 50 | "Please login using @itbhu.ac.in student email id only") 51 | name = jwt['name'] 52 | UserModel = get_user_model() 53 | user = UserModel() 54 | user.username = jwt['uid'] 55 | user.email = email 56 | user.save() 57 | current_user = user 58 | department = Student.get_department(email) 59 | year_of_joining = Student.get_year(email) 60 | # pylint: disable=no-member 61 | profile = UserProfile.objects.create( 62 | uid=uid, user=user, name=name, email=email, department=department, 63 | year_of_joining=year_of_joining, photo_url=jwt['picture']) 64 | 65 | attrs['user'] = current_user 66 | logger.info('[POST Response] User Login : %s', current_user) 67 | return attrs 68 | 69 | 70 | class ProfileSerializer(serializers.ModelSerializer): 71 | phone_number = serializers.CharField(max_length=15, validators=[ 72 | phone_regex, ], allow_blank=True) 73 | club_subscriptions = serializers.SerializerMethodField() 74 | entity_subscriptions = serializers.SerializerMethodField() 75 | club_privileges = serializers.SerializerMethodField() 76 | entity_privileges = serializers.SerializerMethodField() 77 | 78 | @swagger_serializer_method(serializer_or_field=ClubSerializer(many=True)) 79 | def get_club_subscriptions(self, obj): 80 | """ 81 | User subscriptions for the clubs. 82 | """ 83 | clubs = obj.club_subscriptions.all().select_related('council') 84 | return ClubSerializer(clubs, many=True).data 85 | 86 | @swagger_serializer_method(serializer_or_field=EntitySerializer(many=True)) 87 | def get_entity_subscriptions(self, obj): 88 | """ 89 | User subscriptions for entities. 90 | """ 91 | entities = obj.entity_subscriptions.all() 92 | return EntitySerializer(entities, many=True).data 93 | 94 | @swagger_serializer_method(serializer_or_field=ClubSerializer(many=True)) 95 | def get_club_privileges(self, obj): 96 | """ 97 | Privileges of the user for creating workshops. 98 | Clubs - Secretary / Joint Secretary, 99 | Councils - General Secretary / Joint General Secretary. 100 | """ 101 | clubs = obj.get_club_privileges() 102 | return ClubSerializer(clubs, many=True).data 103 | 104 | @swagger_serializer_method(serializer_or_field=EntitySerializer(many=True)) 105 | def get_entity_privileges(self, obj): 106 | """ 107 | Privileges of the user for creating workshops. 108 | Entities - Points of Contact 109 | """ 110 | entities = obj.get_entity_privileges() 111 | return EntitySerializer(entities, many=True).data 112 | 113 | def update(self, instance, validated_data): 114 | name = validated_data['name'] 115 | phone_number = validated_data['phone_number'] 116 | # pylint: disable=no-member 117 | instance.name = name 118 | instance.phone_number = phone_number 119 | instance.photo_url = FirebaseAPI.get_photo_url( 120 | instance.uid) # update photo_url of user 121 | instance.save() 122 | logger.info('[PUT/PATCH Response] (%s) : %s', instance, validated_data) 123 | return instance 124 | 125 | class Meta: 126 | model = UserProfile 127 | read_only_fields = ( 128 | 'id', 'email', 'department', 'year_of_joining', 'club_subscriptions', 129 | 'entity_subscriptions', 'club_privileges', 'entity_privileges', 'photo_url', 130 | 'can_post_notice', 'can_add_parliament_details') 131 | fields = ( 132 | 'id', 'name', 'email', 'phone_number', 'department', 'year_of_joining', 133 | 'club_subscriptions', 'entity_subscriptions', 'club_privileges', 'entity_privileges', 134 | 'photo_url', 'can_post_notice', 'can_add_parliament_details') 135 | 136 | 137 | class ProfileSearchSerializer(serializers.Serializer): 138 | search_by = serializers.ChoiceField( 139 | choices=['name', 'email'], default='email') 140 | search_string = serializers.CharField(max_length=255) 141 | 142 | def validate_search_string(self, search_string): 143 | """ 144 | Validate the search_string field, length must be greater than 3. 145 | """ 146 | if len(search_string) < 3: 147 | raise serializers.ValidationError( 148 | "The length of search field must be atleast 3") 149 | return search_string 150 | 151 | def save(self, **kwargs): 152 | data = self.validated_data 153 | search_by = data['search_by'] 154 | search_string = data['search_string'] 155 | # pylint: disable=no-member 156 | profile = UserProfile.objects.none() 157 | if search_by == 'name': 158 | profile = UserProfile.objects.filter( 159 | name__icontains=search_string)[:10] 160 | elif search_by == 'email': 161 | profile = UserProfile.objects.filter( 162 | email__icontains=search_string)[:10] 163 | return profile 164 | -------------------------------------------------------------------------------- /workshop/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | from .models import UserProfile 3 | 4 | 5 | class AllowWorkshopHead(permissions.BasePermission): 6 | message = "You are not authorized to perform this task" 7 | 8 | def has_object_permission(self, request, view, obj): 9 | if not request.user.is_authenticated: 10 | return False 11 | # pylint: disable=no-member 12 | profile = UserProfile.objects.get(user=request.user) 13 | # pylint: disable=no-member 14 | if obj.club is not None: 15 | club = obj.club 16 | if club in profile.get_club_privileges(): 17 | return True 18 | elif obj.entity is not None: 19 | entity = obj.entity 20 | if entity in profile.get_entity_privileges(): 21 | return True 22 | return False 23 | 24 | 25 | class AllowWorkshopHeadOrContact(permissions.BasePermission): 26 | message = "You are not authorized to perform this task" 27 | 28 | def has_object_permission(self, request, view, obj): 29 | if request.method in permissions.SAFE_METHODS: 30 | return True 31 | if not request.user.is_authenticated: 32 | return False 33 | # pylint: disable=no-member 34 | profile = UserProfile.objects.get(user=request.user) 35 | # pylint: disable=no-member 36 | if obj.club is not None: 37 | club = obj.club 38 | if (club in profile.get_club_privileges() 39 | or obj in profile.organized_workshops.all()): 40 | return True 41 | elif obj.entity is not None: 42 | entity = obj.entity 43 | if (entity in profile.get_entity_privileges() 44 | or obj in profile.organized_workshops.all()): 45 | return True 46 | return False 47 | 48 | 49 | class AllowAnyClubHead(permissions.BasePermission): 50 | message = "You are not authorized to perform this task" 51 | 52 | def has_permission(self, request, view): 53 | if not request.user.is_authenticated: 54 | return False 55 | # pylint: disable=no-member 56 | profile = UserProfile.objects.get(user=request.user) 57 | if profile.get_club_privileges(): 58 | return True 59 | return False 60 | 61 | 62 | class AllowAnyClubOrEntityHead(permissions.BasePermission): 63 | message = "You are not authorized to perform this task" 64 | 65 | def has_permission(self, request, view): 66 | if not request.user.is_authenticated: 67 | return False 68 | # pylint: disable=no-member 69 | profile = UserProfile.objects.get(user=request.user) 70 | if profile.get_club_privileges() or profile.get_entity_privileges(): 71 | return True 72 | return False 73 | 74 | 75 | class AllowAnyClubHeadOrContact(permissions.BasePermission): 76 | message = "You are not authorized to perform this task" 77 | 78 | def has_permission(self, request, view): 79 | if not request.user.is_authenticated: 80 | return False 81 | # pylint: disable=no-member 82 | profile = UserProfile.objects.get(user=request.user) 83 | if profile.get_club_privileges() or profile.get_workshop_privileges(): 84 | return True 85 | return False 86 | 87 | 88 | class AllowAnyEntityHeadOrContact(permissions.BasePermission): 89 | message = "You are not authorized to perform this task" 90 | 91 | def has_permission(self, request, view): 92 | if not request.user.is_authenticated: 93 | return False 94 | # pylint: disable=no-member 95 | profile = UserProfile.objects.get(user=request.user) 96 | if profile.get_entity_privileges() or profile.get_workshop_privileges(): 97 | return True 98 | return False 99 | 100 | 101 | class AllowWorkshopHeadOrContactForResource(permissions.BasePermission): 102 | message = "You are not authorized to perform this task" 103 | 104 | def has_object_permission(self, request, view, obj): 105 | if request.method in permissions.SAFE_METHODS: 106 | return True 107 | if not request.user.is_authenticated: 108 | return False 109 | # pylint: disable=no-member 110 | profile = UserProfile.objects.get(user=request.user) 111 | # pylint: disable=no-member 112 | if obj.workshop.club is not None: 113 | club = obj.workshop.club 114 | if (club in profile.get_club_privileges() 115 | or obj.workshop in profile.organized_workshops.all()): 116 | return True 117 | elif obj.workshop.entity is not None: 118 | entity = obj.workshop.entity 119 | if (entity in profile.get_entity_privileges() 120 | or obj.workshop in profile.organized_workshops.all()): 121 | return True 122 | return False 123 | 124 | 125 | class AllowParticularClubHead(permissions.BasePermission): 126 | message = "You are not authorized to perform this task" 127 | 128 | def has_object_permission(self, request, view, obj): 129 | if request.method in permissions.SAFE_METHODS: 130 | return True 131 | if not request.user.is_authenticated: 132 | return False 133 | # pylint: disable=no-member 134 | profile = UserProfile.objects.get(user=request.user) 135 | club = obj 136 | if club in profile.get_club_privileges(): 137 | return True 138 | return False 139 | 140 | 141 | class AllowParticularCouncilHead(permissions.BasePermission): 142 | message = "You are not authorized to perform this task" 143 | 144 | def has_object_permission(self, request, view, obj): 145 | if request.method in permissions.SAFE_METHODS: 146 | return True 147 | if not request.user.is_authenticated: 148 | return False 149 | # pylint: disable=no-member 150 | profile = UserProfile.objects.get(user=request.user) 151 | council = obj 152 | if council in profile.get_council_privileges(): 153 | return True 154 | return False 155 | 156 | 157 | class AllowParticularEntityHead(permissions.BasePermission): 158 | message = "You are not authorized to perform this task" 159 | 160 | def has_object_permission(self, request, view, obj): 161 | if request.method in permissions.SAFE_METHODS: 162 | return True 163 | if not request.user.is_authenticated: 164 | return False 165 | # pylint: disable=no-member 166 | profile = UserProfile.objects.get(user=request.user) 167 | entity = obj 168 | if entity in profile.get_entity_privileges(): 169 | return True 170 | return False 171 | 172 | 173 | class AllowAnyEntityHead(permissions.BasePermission): 174 | message = "You are not authorized to perform this task" 175 | 176 | def has_permission(self, request, view): 177 | if not request.user.is_authenticated: 178 | return False 179 | # pylint: disable=no-member 180 | profile = UserProfile.objects.get(user=request.user) 181 | if profile.get_entity_privileges(): 182 | return True 183 | return False 184 | -------------------------------------------------------------------------------- /workshop/models.py: -------------------------------------------------------------------------------- 1 | import re 2 | from django.db import models 3 | from django.core.exceptions import ValidationError 4 | from authentication.models import UserProfile 5 | 6 | def validate_kebab_case(string): 7 | """ 8 | Validate whether the string is in kebab-case 9 | """ 10 | pattern = re.compile(r"^[a-z0-9]+(\-[a-z0-9]+)*$") 11 | if not pattern.match(string): 12 | raise ValidationError( 13 | "The string must contain only dashes or lowercase english alphabets or digits") 14 | 15 | 16 | class Council(models.Model): 17 | name = models.CharField(max_length=50) 18 | description = models.TextField(null=True, blank=True) 19 | gensec = models.ForeignKey(UserProfile, on_delete=models.SET_NULL, null=True, blank=True, 20 | related_name='council_gensec', verbose_name='General Secretary') 21 | joint_gensec = models.ManyToManyField(UserProfile, blank=True, 22 | related_name='council_joint_gensec', 23 | verbose_name='Joint General Secretary') 24 | small_image_url = models.URLField(null=True, blank=True) 25 | large_image_url = models.URLField(null=True, blank=True) 26 | website_url = models.URLField(null=True, blank=True) 27 | facebook_url = models.URLField(null=True, blank=True) 28 | twitter_url = models.URLField(null=True, blank=True) 29 | instagram_url = models.URLField(null=True, blank=True) 30 | linkedin_url = models.URLField(null=True, blank=True) 31 | youtube_url = models.URLField(null=True, blank=True) 32 | 33 | def __str__(self): 34 | return f'{self.name}' 35 | 36 | 37 | class Club(models.Model): 38 | name = models.CharField(max_length=50) 39 | description = models.TextField(null=True, blank=True) 40 | council = models.ForeignKey(Council, on_delete=models.CASCADE, related_name='clubs') 41 | secy = models.ForeignKey(UserProfile, on_delete=models.SET_NULL, null=True, 42 | blank=True, related_name='club_secy', verbose_name='Secretary') 43 | joint_secy = models.ManyToManyField(UserProfile, blank=True, related_name='club_joint_secy', 44 | verbose_name='Joint Secretary') 45 | subscribed_users = models.ManyToManyField(UserProfile, blank=True, 46 | related_name='club_subscriptions') 47 | small_image_url = models.URLField(null=True, blank=True) 48 | large_image_url = models.URLField(null=True, blank=True) 49 | website_url = models.URLField(null=True, blank=True) 50 | facebook_url = models.URLField(null=True, blank=True) 51 | twitter_url = models.URLField(null=True, blank=True) 52 | instagram_url = models.URLField(null=True, blank=True) 53 | linkedin_url = models.URLField(null=True, blank=True) 54 | youtube_url = models.URLField(null=True, blank=True) 55 | 56 | def __str__(self): 57 | return f'{self.name}' 58 | 59 | 60 | class Entity(models.Model): 61 | name = models.CharField(max_length=50) 62 | description = models.TextField(null=True, blank=True) 63 | is_permanent = models.BooleanField(default = False) 64 | is_highlighted = models.BooleanField(default = False) 65 | point_of_contact = models.ManyToManyField(UserProfile, blank=True, 66 | related_name='entity_point_of_contact', 67 | verbose_name='Point of Contact') 68 | subscribed_users = models.ManyToManyField(UserProfile, blank=True, 69 | related_name='entity_subscriptions') 70 | small_image_url = models.URLField(null=True, blank=True) 71 | large_image_url = models.URLField(null=True, blank=True) 72 | website_url = models.URLField(null=True, blank=True) 73 | facebook_url = models.URLField(null=True, blank=True) 74 | twitter_url = models.URLField(null=True, blank=True) 75 | instagram_url = models.URLField(null=True, blank=True) 76 | linkedin_url = models.URLField(null=True, blank=True) 77 | youtube_url = models.URLField(null=True, blank=True) 78 | 79 | def __str__(self): 80 | return f'{self.name}' 81 | 82 | 83 | class Tag(models.Model): 84 | class Meta: 85 | indexes = [ 86 | models.Index(fields=['tag_name', 'club']), 87 | models.Index(fields=['tag_name', 'entity']), 88 | models.Index(fields=['club']), 89 | models.Index(fields=['entity'])] 90 | tag_name = models.CharField( 91 | max_length=50, validators=[validate_kebab_case]) 92 | club = models.ForeignKey(Club, on_delete=models.CASCADE, related_name='tags', 93 | blank = True, null = True) 94 | entity = models.ForeignKey(Entity, on_delete=models.CASCADE, related_name='entity_tags', 95 | blank = True, null = True) 96 | 97 | def __str__(self): 98 | return f'{self.tag_name}' 99 | 100 | 101 | class Workshop(models.Model): 102 | class Meta: 103 | indexes = [ 104 | models.Index(fields=['date', 'time']), 105 | models.Index(fields=['-date', '-time']), 106 | models.Index(fields=['club', '-date']), 107 | models.Index(fields=['club', 'date']), 108 | models.Index(fields=['title']), 109 | models.Index(fields=['location']), 110 | models.Index(fields=['audience']), 111 | ] 112 | title = models.CharField(max_length=50) 113 | description = models.TextField(null=True, blank=True) 114 | entity = models.ForeignKey(Entity, on_delete=models.CASCADE, related_name='entity_workshops', 115 | blank=True, null = True) 116 | club = models.ForeignKey(Club, on_delete=models.CASCADE, related_name='workshops', 117 | blank=True, null = True) 118 | is_workshop = models.BooleanField(default=True) # True if it is a workshop, False for an event 119 | date = models.DateField() 120 | time = models.TimeField(blank=True, null=True) 121 | location = models.CharField(blank=True, max_length=100) 122 | latitude = models.DecimalField(blank=True, null=True, max_digits=9, decimal_places=6) 123 | longitude = models.DecimalField(blank=True, null=True, max_digits=9, decimal_places=6) 124 | audience = models.CharField(blank=True, max_length=100) 125 | contacts = models.ManyToManyField(UserProfile, blank=True, related_name='organized_workshops') 126 | interested_users = models.ManyToManyField(UserProfile, blank=True, 127 | related_name='interested_workshops') 128 | image_url = models.URLField(null=True, blank=True) 129 | tags = models.ManyToManyField(Tag, blank=True, related_name='tagged_workshops') 130 | link = models.URLField(null=True, blank=True) 131 | 132 | def __str__(self): 133 | return f'{self.title}' 134 | 135 | 136 | class WorkshopResource(models.Model): 137 | RESOURCE_TYPES = [ 138 | ('Prerequisite', 'Prerequisite'), 139 | ('Material', 'Material') 140 | ] 141 | name = models.CharField(max_length=100) 142 | link = models.URLField() 143 | workshop = models.ForeignKey(Workshop, on_delete=models.CASCADE, 144 | related_name='resources') 145 | resource_type = models.CharField(choices=RESOURCE_TYPES, max_length=20) 146 | -------------------------------------------------------------------------------- /parliament_detail/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics, permissions ,status 2 | from rest_framework.response import Response 3 | from django.shortcuts import get_object_or_404 4 | 5 | from authentication.models import UserProfile 6 | from .models import Contact, Update, Suggestion, Committee 7 | from .permissions import AllowParliamentHead 8 | from noticeboard.permissions import AllowNoticeContact 9 | from .serializers import ( 10 | ContactsSerializer, ContactCreateSerializer, 11 | UpdateListSerializer, UpdateDetailSerializer, UpdateCreateSerializer, 12 | SuggestionListSerializer, SuggestionDetailSerializer, SuggestionCreateSerializer 13 | ) 14 | 15 | class ContactsListView(generics.ListAPIView): 16 | """ 17 | Get All Parliament Contacts 18 | """ 19 | queryset = Contact.objects.all() 20 | permission_classes = (permissions.AllowAny,) 21 | serializer_class = ContactsSerializer 22 | 23 | class ContactsCreateView(generics.CreateAPIView): 24 | """ 25 | Create New Parliament Contact 26 | """ 27 | # pylint: disable=no-member 28 | queryset = Contact.objects.all() 29 | permission_classes = (permissions.IsAuthenticated, AllowParliamentHead,) 30 | serializer_class = ContactCreateSerializer 31 | 32 | class ContactDetailView(generics.RetrieveUpdateDestroyAPIView): 33 | """ 34 | Update and Delete a Parliament Contact 35 | """ 36 | permission_classes = (permissions.IsAuthenticated, AllowParliamentHead,) 37 | serializer_class = ContactsSerializer 38 | # pylint: disable=no-member 39 | queryset = Contact.objects.all() 40 | 41 | class UpdatesListView(generics.ListAPIView): 42 | """ 43 | Get All Parliament Updates 44 | """ 45 | queryset = ( 46 | # pylint: disable=no-member 47 | Update.objects.all() 48 | .order_by("-date") 49 | ) 50 | permission_classes = (permissions.AllowAny,) 51 | serializer_class = UpdateListSerializer 52 | 53 | class UpdatesCreateView(generics.CreateAPIView): 54 | """ 55 | Create New Parliament Update 56 | Users with can_add_parliament_details or can_add_notice permissions can create updates. 57 | """ 58 | # pylint: disable=no-member 59 | permission_classes = (permissions.IsAuthenticated, AllowParliamentHead | AllowNoticeContact,) 60 | queryset = Update.objects.all() 61 | serializer_class = UpdateCreateSerializer 62 | 63 | def perform_create(self, serializer): 64 | user = get_object_or_404(UserProfile,user=self.request.user) 65 | serializer.save(author=user) 66 | 67 | class UpdateDetailView(generics.RetrieveUpdateDestroyAPIView): 68 | """ 69 | Update and Delete a Parliament Update. 70 | Users with can_add_parliament_details or can_add_notice permissions can update and delete. 71 | """ 72 | permission_classes = (permissions.IsAuthenticated, AllowParliamentHead | AllowNoticeContact,) 73 | serializer_class = UpdateDetailSerializer 74 | 75 | def get_queryset(self): 76 | if(self.request.user.is_authenticated): 77 | user = get_object_or_404(UserProfile,user=self.request.user) 78 | return Update.objects.filter(author=user) 79 | return 80 | 81 | class CommitteeUpdatesListView(generics.ListAPIView): 82 | """ 83 | Get All Updates for a Committee 84 | """ 85 | permission_classes = (permissions.AllowAny,) 86 | serializer_class = UpdateListSerializer 87 | 88 | def get_queryset(self): 89 | committee = get_object_or_404(Committee,id=self.kwargs['committeeId']) 90 | return Update.objects.filter(committee=committee) 91 | 92 | class SuggestionsListView(generics.ListAPIView): 93 | """ 94 | Get All Parliament Suggestions 95 | """ 96 | queryset = ( 97 | # pylint: disable=no-member 98 | Suggestion.objects.all() 99 | .order_by("-upvotes", "-date") 100 | ) 101 | permission_classes = (permissions.AllowAny,) 102 | serializer_class = SuggestionListSerializer 103 | 104 | class SuggestionsCreateView(generics.CreateAPIView): 105 | """ 106 | Create New Parliament Suggestion 107 | """ 108 | # pylint: disable=no-member 109 | permission_classes = (permissions.IsAuthenticated,) 110 | queryset = Suggestion.objects.all() 111 | serializer_class = SuggestionCreateSerializer 112 | 113 | def perform_create(self, serializer): 114 | user = get_object_or_404(UserProfile,user=self.request.user) 115 | serializer.save(author=user) 116 | 117 | 118 | class SuggestionDetailView(generics.RetrieveUpdateDestroyAPIView): 119 | """ 120 | get: 121 | Get a suggestion using its id. Authentication is not required for this method. 122 | 123 | put: 124 | Update a suggestion using its id. A user can only update a suggestion written by him/her. 125 | Users with can_add_parliament_details or can_add_notice permissions can however update any suggestion. 126 | 127 | patch: 128 | Update a suggestion using its id. A user can only update a suggestion written by him/her. 129 | Users with can_add_parliament_details or can_add_notice permissions can however update any suggestion. 130 | 131 | delete: 132 | Delete a suggestion using its id. A user can only update a suggestion written by him/her. 133 | Users with can_add_parliament_details or can_add_notice permissions can however delete any suggestion. 134 | """ 135 | serializer_class = SuggestionDetailSerializer 136 | 137 | def get_permissions(self): 138 | if(self.request.method == 'GET'): 139 | return [permissions.AllowAny()] 140 | return [permissions.IsAuthenticated()] 141 | 142 | 143 | def get_queryset(self): 144 | if (self.request.method=='GET'): 145 | return Suggestion.objects.all() 146 | if(self.request.user.is_authenticated): 147 | user = get_object_or_404(UserProfile,user=self.request.user) 148 | if(user.can_add_parliament_details or user.can_post_notice): 149 | return Suggestion.objects.all() 150 | return Suggestion.objects.filter(author=user) 151 | return Response( 152 | {"Message": "Authentication credentials were not provided."}, status=status.HTTP_401_UNAUTHORIZED 153 | ) 154 | 155 | 156 | class SuggestionUpvoteView(generics.GenericAPIView): 157 | """ 158 | Upvote a Parliament Suggestion 159 | """ 160 | # pylint: disable=no-member 161 | queryset = Suggestion.objects.all() 162 | permission_classes = (permissions.IsAuthenticated,) 163 | serializer_class = SuggestionDetailSerializer 164 | 165 | def get(self, request, pk): 166 | suggestion = get_object_or_404(self.queryset,id=pk) 167 | user = UserProfile.objects.get(user=request.user) 168 | if suggestion.voters.filter(id = user.id).exists(): 169 | return Response( 170 | {"Error": "You can vote only once"}, status=status.HTTP_208_ALREADY_REPORTED 171 | ) 172 | suggestion.upvotes += 1 173 | suggestion.voters.add(user) 174 | suggestion.save() 175 | return Response( 176 | {"Message": "Upvoted successfully"}, status=status.HTTP_200_OK 177 | ) 178 | 179 | class SuggestionDownvoteView(generics.GenericAPIView): 180 | """ 181 | Downvote a Parliament Suggestion 182 | """ 183 | # pylint: disable=no-member 184 | queryset = Suggestion.objects.all() 185 | permission_classes = (permissions.IsAuthenticated,) 186 | serializer_class = SuggestionDetailSerializer 187 | 188 | def get(self, request, pk): 189 | suggestion = get_object_or_404(self.queryset,id=pk) 190 | user = UserProfile.objects.get(user=request.user) 191 | 192 | if suggestion.voters.filter(id = user.id).exists(): 193 | return Response( 194 | {"Error": "You can vote only once"}, status=status.HTTP_208_ALREADY_REPORTED 195 | ) 196 | suggestion.downvotes += 1 197 | suggestion.voters.add(user) 198 | suggestion.save() 199 | return Response( 200 | {"Message": "Downvoted successfully"}, status=status.HTTP_200_OK 201 | ) 202 | --------------------------------------------------------------------------------