From e0611793f64bf031684941fcba35bbcd76a1246c Mon Sep 17 00:00:00 2001 From: Rupika Date: Sun, 3 Feb 2019 00:47:04 -0800 Subject: [PATCH 01/32] Printing the data from the database - need to update the functionality to prevent overwriting --- back/backend/serializers.py | 130 ++++++++++++++++++------------------ back/backend/urls.py | 20 +++--- back/backend/views.py | 76 +++++++++++++++++++-- back/db.sqlite3 | Bin 53248 -> 53248 bytes 4 files changed, 147 insertions(+), 79 deletions(-) diff --git a/back/backend/serializers.py b/back/backend/serializers.py index 1b162f4..16d78e4 100644 --- a/back/backend/serializers.py +++ b/back/backend/serializers.py @@ -1,66 +1,66 @@ -# Rupika Dikkala -# January 23, 2019 -# File contains serializers needed -# to set up API end points - -from rest_framework import serializers -from . import models - -# serializer for reports -class ReportSerializer(serializers.ModelSerializer): - # user id is foreign key - user_id = serializers.PrimaryKeyRelatedField(many=False, read_only=True) - - class Meta: - fields = ( - 'user_id', - 'title', - 'date_created', - # 'data_submitted', - 'submitted', - ) - model = models.Report - - -# section serializer -class SectionSerializer(serializers.ModelSerializer): - # report id foriegn key - report_id = serializers.PrimaryKeyRelatedField(many=True, read_only=True) - - - class Meta: - fields = ( - 'report_id', - 'completed', - 'title', - 'html_description', - 'number', - ) - model = models.Section - - -class FieldSerializer(serializers.ModelSerializer): - # section_id is foriegn key - section_id = serializers.PrimaryKeyRelatedField(many=True, read_only=True) - - class Meta: - fields = ( - 'section_id', - 'label', - 'number', - 'type', - 'completed', - ) - model = models.Field - - -class DataSerializer(serializers.ModelSerializer): - field_id = serializers.PrimaryKeyRelatedField(many=False, read_only=True) - - - - - - - +# # Rupika Dikkala +# # January 23, 2019 +# # File contains serializers needed +# # to set up API end points +# +# from rest_framework import serializers +# from . import models +# +# # serializer for reports +# class ReportSerializer(serializers.ModelSerializer): +# # user id is foreign key +# user_id = serializers.PrimaryKeyRelatedField(many=False, read_only=True) +# +# class Meta: +# fields = ( +# 'user_id', +# 'title', +# 'date_created', +# # 'data_submitted', +# 'submitted', +# ) +# model = models.Report +# +# +# # section serializer +# class SectionSerializer(serializers.ModelSerializer): +# # report id foriegn key +# report_id = serializers.PrimaryKeyRelatedField(many=True, read_only=True) +# +# +# class Meta: +# fields = ( +# 'report_id', +# 'completed', +# 'title', +# 'html_description', +# 'number', +# ) +# model = models.Section +# +# +# class FieldSerializer(serializers.ModelSerializer): +# # section_id is foriegn key +# section_id = serializers.PrimaryKeyRelatedField(many=True, read_only=True) +# +# class Meta: +# fields = ( +# 'section_id', +# 'label', +# 'number', +# 'type', +# 'completed', +# ) +# model = models.Field +# +# +# class DataSerializer(serializers.ModelSerializer): +# field_id = serializers.PrimaryKeyRelatedField(many=False, read_only=True) +# +# +# +# +# +# +# diff --git a/back/backend/urls.py b/back/backend/urls.py index 8e0cada..921ff01 100644 --- a/back/backend/urls.py +++ b/back/backend/urls.py @@ -5,16 +5,18 @@ from rest_framework.urlpatterns import format_suffix_patterns from . import views urlpatterns = [ - #path('', views.List.as_view()), - #path('/', views.Detail.as_view()), + # path('', views.List.as_view()), + # path('/', views.Detail.as_view()), + path('print', views.print_all_reports), - path('report', views.report), - path('reports', views.reports), - path('report/', views.report_detail), - path('report//section/', views.section), - path('account', views.account), - path('account/login', views.account_login), - path('account/logout', views.account_logout), + # + # path('report', views.report), + # path('reports', views.reports), + # path('report/', views.report_detail), + # path('report//section/', views.section), + # path('account', views.account), + # path('account/login', views.account_login), + # path('account/logout', views.account_logout), ] urlpatterns = format_suffix_patterns(urlpatterns) \ No newline at end of file diff --git a/back/backend/views.py b/back/backend/views.py index 1f99059..2c95510 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -8,13 +8,78 @@ from .serializers import * # Sample view using generics -class List(generics.ListCreateAPIView): - queryset = Report.objects.all() - serializer_class = ReportSerializer +# class List(generics.ListCreateAPIView): +# queryset = Report.objects.all() +# serializer_class = ReportSerializer +# +# class Detail(generics.RetrieveUpdateDestroyAPIView): +# queryset = Report.objects.all() +# serializer_class = ReportSerializer -class Detail(generics.RetrieveUpdateDestroyAPIView): + +def print_all_reports(self): + data = {} queryset = Report.objects.all() - serializer_class = ReportSerializer + for i in queryset: + data = { + "title": i.title, + "date_created": i.date_created, + "submitted": i.submitted, + "date_submitted": i.date_submitted, + "sections": get_sections(i.id), + } + + return JsonResponse(data) + +def get_sections(r_id): + section_set = {"section_set": []} + queryset = Section.objects.filter(report_id=r_id) + # queryset = Section.objects.all() + for i in queryset: + inner_section = { + "id": i.id, + "completed": i.completed, + "title": i.title, + "html_description": i.html_description, + "fields": get_fields(i.id), + } + # section_set.update(inner_section) + section_set["section_set"].append(inner_section.copy()) + + return section_set + # return JsonResponse(full) + + +def get_fields(s_id): + field_set = {"fields": []} + queryset = Field.objects.filter(section_id=s_id) + # queryset = Field.objects.all() + count = 0 + for i in queryset: + temp = "field" + str(count) + inner_field = {i.label: { + "label": i.label, + "type": i.type, + "value": i.number, + }} + print("PRINT FIELD") + print(i.label) + print(i.type) + print(i.number) + # field_set.append(inner_field) + field_set["fields"].append(inner_field.copy()) + # field_set.update(inner_field) + count += 1 + + print("COUNT = {}".format(count)) + return field_set + # return JsonResponse(field_set) + + + + + + # API Endpoints @@ -85,6 +150,7 @@ def report(request): } return JsonResponse(data) +# List of reports @api_view(['GET']) def reports(request): data = { diff --git a/back/db.sqlite3 b/back/db.sqlite3 index bfc38f728890df0c057a06cad169fe8f1804510a..42abd451cc1aa0043c727d3948c91babae07e215 100644 GIT binary patch delta 407 zcmZozz}&Ead4e>f-$WT_M!$^-iN=D)3I=9YMkZD!mU;$87KWB4n=cs~)o?H|wlFXq zVr<#0$Wg&q-(=0i>f6HVSXyk6ZdRIIVPIaGo@kPuY;KraUYwMgpJQ2>Tb^W8;_s4e z?C;{18JX*q73JcT?VIJ6;g{u?6=@Wf?dJ|;h5H&r<@#3ohj89wMR=tpy1P{+I(wRVX1N;p<^~!VMY+2gMrB1B`sR8XM7cOt`58r4 zL{_DnMrC=HM}`1pvZAtlvm#9*vm%Xw^yG<~g}HLFJ+tyNeSE*4JF~nTvm+yJYne7b+Ak*n0O|{T=>Px# delta 106 zcmZozz}&Ead4e>f_e2?IM(>RYiN=D43I+yNMn+bK#(I{<7KWxqn=cs~)vz%#9b#ZQ zv{{j32NOq=H6yEU3#;Sg2ip}kzuF|l$i~Qghk^OdW Date: Sun, 3 Feb 2019 16:56:34 -0800 Subject: [PATCH 02/32] Token authentication, api endpoints and 'BearerAuthentication' working. --- Pipfile | 11 +++++++++++ Pipfile.lock | 20 ++++++++++++++++++++ back/Pipfile | 2 +- back/Pipfile.lock | 16 +++++++++++++++- back/backend/__init__.py | 0 back/backend/urls.py | 5 +---- back/backend/views.py | 23 ++--------------------- back/db.sqlite3 | Bin 53248 -> 59392 bytes back/reimbursinator/custom_auth.py | 9 +++++++++ back/reimbursinator/settings.py | 11 +++++++++-- back/reimbursinator/urls.py | 4 +++- back/users/__init__.py | 0 12 files changed, 71 insertions(+), 30 deletions(-) create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 back/backend/__init__.py create mode 100644 back/reimbursinator/custom_auth.py create mode 100644 back/users/__init__.py diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..b723d01 --- /dev/null +++ b/Pipfile @@ -0,0 +1,11 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] + +[requires] +python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..9a51a28 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,20 @@ +{ + "_meta": { + "hash": { + "sha256": "7e7ef69da7248742e869378f8421880cf8f0017f96d94d086813baa518a65489" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": {}, + "develop": {} +} diff --git a/back/Pipfile b/back/Pipfile index b2fa8cc..54943ec 100644 --- a/back/Pipfile +++ b/back/Pipfile @@ -9,8 +9,8 @@ verify_ssl = true django = "==2.1.5" django-cors-headers = "==2.4.0" djangorestframework = "==3.8.2" - gunicorn = "==19.6.0" +django-rest-auth = "==0.9.3" [requires] python_version = "3.5" diff --git a/back/Pipfile.lock b/back/Pipfile.lock index 4527d5b..e493330 100644 --- a/back/Pipfile.lock +++ b/back/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b5222b4256c8f09a9b1b1d380285fa65c443f84d28dc03450684fca84b38a26b" + "sha256": "d3bf402a934e168cbdc04022effcdb9ff8d4fde5b83d79bb388ad2a4c547894a" }, "pipfile-spec": 6, "requires": { @@ -32,6 +32,13 @@ "index": "pypi", "version": "==2.4.0" }, + "django-rest-auth": { + "hashes": [ + "sha256:ad155a0ed1061b32e3e46c9b25686e397644fd6acfd35d5c03bc6b9d2fc6c82a" + ], + "index": "pypi", + "version": "==0.9.3" + }, "djangorestframework": { "hashes": [ "sha256:b6714c3e4b0f8d524f193c91ecf5f5450092c2145439ac2769711f7eba89a9d9", @@ -54,6 +61,13 @@ "sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c" ], "version": "==2018.9" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" } }, "develop": {} diff --git a/back/backend/__init__.py b/back/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/back/backend/urls.py b/back/backend/urls.py index 8e0cada..1f1cdcd 100644 --- a/back/backend/urls.py +++ b/back/backend/urls.py @@ -12,9 +12,6 @@ urlpatterns = [ path('reports', views.reports), path('report/', views.report_detail), path('report//section/', views.section), - path('account', views.account), - path('account/login', views.account_login), - path('account/logout', views.account_logout), ] -urlpatterns = format_suffix_patterns(urlpatterns) \ No newline at end of file +urlpatterns = format_suffix_patterns(urlpatterns) diff --git a/back/backend/views.py b/back/backend/views.py index 1f99059..68d6acb 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -87,6 +87,8 @@ def report(request): @api_view(['GET']) def reports(request): + print("User: ", request.user) + print("User id: ", request.user.id) data = { "reports": [ { @@ -199,24 +201,3 @@ def section(request, report_pk, section_pk): } } return JsonResponse(data) - -@api_view(['POST']) -def account(request): - ''' - Create a new user account - ''' - return JsonResponse({"message": "Account creation successful."}) - -@api_view(['POST']) -def account_login(request): - ''' - Log in to a user account - ''' - return JsonResponse({"message": "Successfully logged in."}) - -@api_view(['DELETE']) -def account_logout(request): - ''' - Log out from a user account - ''' - return JsonResponse({"message": "User logged out."}) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index bfc38f728890df0c057a06cad169fe8f1804510a..47bfc6a538bd931d6f34bf4ae31df582615a398a 100644 GIT binary patch delta 2231 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 diff --git a/back/reimbursinator/custom_auth.py b/back/reimbursinator/custom_auth.py new file mode 100644 index 0000000..9097e26 --- /dev/null +++ b/back/reimbursinator/custom_auth.py @@ -0,0 +1,9 @@ +from rest_framework.authentication import TokenAuthentication + +class BearerAuthentication(TokenAuthentication): + """ + This class simply changes the expected token keyword to 'Bearer' + from the Django rest authentication default 'Token'. This allows + applications like Postman to work with token authentication. + """ + keyword = "Bearer" diff --git a/back/reimbursinator/settings.py b/back/reimbursinator/settings.py index e274dc5..c9f3c5e 100644 --- a/back/reimbursinator/settings.py +++ b/back/reimbursinator/settings.py @@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/2.1/ref/settings/ """ import os +#from reimbursinator.custom_auth import BearerAuthentication # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -40,6 +41,8 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', # 3rd party 'rest_framework', + 'rest_framework.authtoken', + 'rest_auth', 'corsheaders', # local 'users', @@ -48,8 +51,12 @@ INSTALLED_APPS = [ REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.AllowAny', - ] + 'rest_framework.permissions.IsAuthenticated', + ], + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.SessionAuthentication', + 'reimbursinator.custom_auth.BearerAuthentication', + ], } MIDDLEWARE = [ diff --git a/back/reimbursinator/urls.py b/back/reimbursinator/urls.py index 53beb58..62397e8 100644 --- a/back/reimbursinator/urls.py +++ b/back/reimbursinator/urls.py @@ -12,4 +12,6 @@ from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/v1/', include("backend.urls")), -] \ No newline at end of file + path('api/v1/account/', include('rest_auth.urls')), + path('api-auth/', include('rest_framework.urls')), +] diff --git a/back/users/__init__.py b/back/users/__init__.py new file mode 100644 index 0000000..e69de29 From c8ae149510ea3dc045788ff81ecdcd7e581f6947 Mon Sep 17 00:00:00 2001 From: kououken Date: Sun, 3 Feb 2019 18:30:42 -0800 Subject: [PATCH 03/32] CSRF backend issue fixed. If cookies are maintained, it seems to work. --- back/db.sqlite3 | Bin 59392 -> 59392 bytes back/reimbursinator/settings.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 47bfc6a538bd931d6f34bf4ae31df582615a398a..cb78c4ce8a1b68160cad808fed6c059b6c863fe2 100644 GIT binary patch delta 1853 zcmeH|&u`;I6vypMvf5T0sDu!L6)HatNT|ggd;BAXL$^+Xqn)v`Byl~c5@{Vf{?&Aw zA5KO{-L01UHvJb?+>l^%C^ulaaay50a#-yVIB@5JQ`9B2D;0_BTC#kY=kL7t=6$|% z`w_VP2;6&vzjJhLgTM35XFtFtd0Bu(5f&x5s>+J0OH(NQ{P`l_%3SUtf0rvC9cc%L zYxx4cTUZbGT&de_LvJ6#K2&b)x``jj?Jn9CdagVSEV~@wumK&m&ZyA|Xjno7HW&^& zAr0e%7;fO$=GX}vf&-fYwW~2T_Ea<0JMQMq?xxgabhGNUDrMH%FcmZO8LpcjARJzg zoVqCyhy|zarw*%0R;3wPbvGhL4U(`VS;qBI3)V>Yfvz(;aUlXK^>#jYu5QO0!o>%3%vO2Xw>iUC7Ly>6v45SNI4DqP`-) z6;WFj#3Is*2(BUtX|jB{1`bXeHkSIHpQbSklcCpk$0-_&b*1mM1E}l{{T@l0k;6*N zvT2O%+6WtQVAUN+?M6zB62h<~l1gbzDyHnfTGk9V!t6N>J4-7_gH2c#-OBNm2f?Q@ zW~H%JH&Z&(U~ZUc$+&_A!a7;wBZ(R{frQS8Fh8XRjfvrpE|w+=MM+uJbxlL!;TnHh z+3}N;<>{{vUguu|V8Vf4zzLXu$#m)37C3kpV7@i-2SVVdN#7s9^j4~?eRm(V-E9pj z``tt-%z`d!510jAHgx%S0A6UdJA3_j)Pv$Mo&J9ET0TqbJ_nwH``}0LMV8h8Y`qEA z`S~+@HunmYMN~MyEEebM1{as-Pdq<;`rX?vzrf}NHvc%n{P>*1=2d?3ef|ocdzhK* z^sTGk<}!;doN{#;H`sP0!gdf%YGa4R5jHv@u}LR$#fo(0TM|W8-th!cl3SjJWVHpo9o(4f}omPob8n7IPf?V f{t0~eKG<6Lud>hn{gcx(6)jWv4HWW#U&#Fhz#TX^ delta 659 zcma))O=}ZD7{_<^Ni5099@Qd21Pjuz^Rl}$n<7M8gN03PY->_1xMsEOCYuJ^ZQ4b! zgnR(Qf}g-^4{;BB6z$DZksf=H9`)b{XhFw_Q1ws`GcYgDZ+`!o**$>W19)`>wfbXs zP;2n`JsG7rLM>`qOv@827-un|pI&5D)Kkw^YLy0(snOhtOsk38MHRN749@P zp6)b-CVafL($ReG`E5P^@-~fLnmIx&$}C3nriq2ly9ISvPTkGGZBw@8hXQxDgTT?B z>#LonV}|Q>KMcxbj@H6CQuC&D`(ec^lbJ@jwCK;4mKw8D3p@6FtyA+BG<#~AmFFvK zHnHVg+q~Blt8TTjUZsoSQZ;%s$e``$bg&Wa#kVg>8)`9PVUjltVsf)vKtr48bCQ$7 zmr+)QM1cg3Ac;rEdN6YxY;;~!__^u4Kx%xHjHe`jUx8!Thc}Y{8g5;MA|e_V6B?Po z|J)Y*z5J)X8Xv#Ab}>#(o{seIk7QIuQ4HC1iT(!B_Z#U8Xc$M1_uxSZrIw4RE+2tm zhB-9|69#uUW-fLpB~P9)>IlwUm$-HMTS`0gE3lBJx|)?|AUIUuP=Y_g>ijWvC311 Date: Sun, 3 Feb 2019 19:40:26 -0800 Subject: [PATCH 04/32] Deleted extraneous Pipfile --- Pipfile | 11 ----------- Pipfile.lock | 20 -------------------- 2 files changed, 31 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock diff --git a/Pipfile b/Pipfile deleted file mode 100644 index b723d01..0000000 --- a/Pipfile +++ /dev/null @@ -1,11 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] - -[packages] - -[requires] -python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 9a51a28..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,20 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "7e7ef69da7248742e869378f8421880cf8f0017f96d94d086813baa518a65489" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": {}, - "develop": {} -} From ebed65f723f57e72ab8b377fbdc401ee02422992 Mon Sep 17 00:00:00 2001 From: Rupika Date: Mon, 4 Feb 2019 09:51:36 -0800 Subject: [PATCH 05/32] Committing my work from api-remove-endpoint to new branch --- back/backend/urls.py | 11 +- back/backend/views.py | 280 +++++++++++++++++++++--------------------- 2 files changed, 145 insertions(+), 146 deletions(-) diff --git a/back/backend/urls.py b/back/backend/urls.py index 921ff01..2ff9fcc 100644 --- a/back/backend/urls.py +++ b/back/backend/urls.py @@ -5,14 +5,13 @@ from rest_framework.urlpatterns import format_suffix_patterns from . import views urlpatterns = [ - # path('', views.List.as_view()), - # path('/', views.Detail.as_view()), - path('print', views.print_all_reports), + # path('print', views.get_reports), + # path('print', views.get_sections), + - # # path('report', views.report), - # path('reports', views.reports), - # path('report/', views.report_detail), + path('reports', views.reports), + path('report/', views.report_detail), # path('report//section/', views.section), # path('account', views.account), # path('account/login', views.account_login), diff --git a/back/backend/views.py b/back/backend/views.py index 2c95510..4974f8c 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -6,83 +6,67 @@ from django.http import JsonResponse from .models import * from .serializers import * -# Sample view using generics -# class List(generics.ListCreateAPIView): -# queryset = Report.objects.all() -# serializer_class = ReportSerializer -# -# class Detail(generics.RetrieveUpdateDestroyAPIView): -# queryset = Report.objects.all() -# serializer_class = ReportSerializer - - -def print_all_reports(self): - data = {} - queryset = Report.objects.all() +# function that prints all the reports +def get_reports(report_pk): + # queryset = Report.objects.all() + queryset = Report.objects.filter(id=report_pk) for i in queryset: data = { - "title": i.title, - "date_created": i.date_created, - "submitted": i.submitted, - "date_submitted": i.date_submitted, - "sections": get_sections(i.id), + "report_pk": report_pk, + "title": i.title, + "date_created": i.date_created, + "submitted": i.submitted, + "date_submitted": i.date_submitted, } + # append the sections for each report + data.update(get_sections(i.id)) - return JsonResponse(data) + # return JsonResponse(data) + return data +# function that gets all the sections +# takes report_id param def get_sections(r_id): - section_set = {"section_set": []} + # create a dict of arrays for section + section_set = {"sections": []} queryset = Section.objects.filter(report_id=r_id) # queryset = Section.objects.all() for i in queryset: - inner_section = { - "id": i.id, - "completed": i.completed, - "title": i.title, - "html_description": i.html_description, - "fields": get_fields(i.id), + data = { + "id": i.id, + "completed": i.completed, + "title": i.title, + "html_description": i.html_description, } - # section_set.update(inner_section) - section_set["section_set"].append(inner_section.copy()) + # append the fields for corresponding section + data.update(get_fields(i.id)) + # append section to the array + section_set["sections"].append(data.copy()) return section_set - # return JsonResponse(full) - +# function that gets all the fields +# takes section_id param def get_fields(s_id): + # create dict of arrays for fields field_set = {"fields": []} queryset = Field.objects.filter(section_id=s_id) # queryset = Field.objects.all() - count = 0 for i in queryset: - temp = "field" + str(count) - inner_field = {i.label: { - "label": i.label, - "type": i.type, - "value": i.number, + data = {i.label: { + "label": i.label, + "type": i.type, + "value": i.number, }} - print("PRINT FIELD") - print(i.label) - print(i.type) - print(i.number) - # field_set.append(inner_field) - field_set["fields"].append(inner_field.copy()) - # field_set.update(inner_field) - count += 1 + # append the fields to array + # use copy() to avoid overwriting + field_set["fields"].append(data.copy()) - print("COUNT = {}".format(count)) return field_set - # return JsonResponse(field_set) - - - - - # API Endpoints - @api_view(['POST']) def report(request): ''' @@ -153,105 +137,121 @@ def report(request): # List of reports @api_view(['GET']) def reports(request): - data = { - "reports": [ - { - "report_pk": 1, - "title": "2018 Portland trip", - "date_created": "2018-05-22T14:56:28.000Z", - "state": "created", - "date_submitted": "0000-00-00T00:00:00.000Z" - }, - { - "report_pk": 2, - "title": "2017 Los Angeles trip", - "date_created": "2017-05-22T14:56:28.000Z", - "state": "submitted", - "date_submitted": "2017-07-22T14:56:28.000Z" - }, - { - "report_pk": 3, - "title": "2017 Denver trip", - "date_created": "2015-04-22T14:56:28.000Z", - "state": "accepted", - "date_submitted": "2015-06-22T14:56:28.000Z" - } - ] - } - return JsonResponse(data) + report_set = {"reports": []} + queryset = Report.objects.all() + for i in queryset: + data = { + "title": i.title, + "date_created": i.date_created, + "submitted": i.submitted, + "date_submitted": i.date_submitted, + } + # append the sections for each report + report_set["reports"].append(data.copy()) + + return JsonResponse(report_set) + + # data = { + # "reports": [ + # { + # "report_pk": 1, + # "title": "2018 Portland trip", + # "date_created": "2018-05-22T14:56:28.000Z", + # "state": "created", + # "date_submitted": "0000-00-00T00:00:00.000Z" + # }, + # { + # "report_pk": 2, + # "title": "2017 Los Angeles trip", + # "date_created": "2017-05-22T14:56:28.000Z", + # "state": "submitted", + # "date_submitted": "2017-07-22T14:56:28.000Z" + # }, + # { + # "report_pk": 3, + # "title": "2017 Denver trip", + # "date_created": "2015-04-22T14:56:28.000Z", + # "state": "accepted", + # "date_submitted": "2015-06-22T14:56:28.000Z" + # } + # ] + # } + # return JsonResponse(data) @api_view(['GET', 'PUT', 'DELETE']) def report_detail(request, report_pk): if request.method == 'GET': - data = { - "report_pk": report_pk, - "title": "2018 Portland trip", - "date_created": "2018-05-22T14:56:28.000Z", - "submitted": False, - "date_submitted": "0000-00-00T00:00:00.000Z", - "sections": [ - { - "id": 1, - "completed": True, - "title": "Flight Info", - "html_description": "

Enter flight details here.

", - "fields": { - "international": { - "label": "International flight", - "type": "boolean", - "value": True - }, - "travel_date": { - "label": "Travel start date", - "type": "date", - "value": "2016-05-22T14:56:28.000Z" - }, - "fare": { - "label": "Fare", - "type": "decimal", - "value": "1024.99" - }, - "lowest_fare_screenshot": { - "label": "Lowest fare screenshot", - "type": "file", - "value": "e92h842jiu49f8..." - }, - "plane_ticket_invoice": { - "label": "Plane ticket invoice PDF", - "type": "file", - "value": "" - } - }, - "rule_violations": [ - { - "error_text": "Plane ticket invoice must be submitted." - } - ] - }, - { - "id": 2, - "completed": False, - "title": "Hotel info", - "html_description": "

If you used a hotel, please enter the details.

", - "fields": { - "total": { - "label": "Total cost", - "type": "decimal" - } - }, - "rule_violations": [ - ] - } - ] - } + data = get_reports(report_pk) + # data = { + # "report_pk": report_pk, + # "title": "2018 Portland trip", + # "date_created": "2018-05-22T14:56:28.000Z", + # "submitted": False, + # "date_submitted": "0000-00-00T00:00:00.000Z", + # "sections": [ + # { + # "id": 1, + # "completed": True, + # "title": "Flight Info", + # "html_description": "

Enter flight details here.

", + # "fields": { + # "international": { + # "label": "International flight", + # "type": "boolean", + # "value": True + # }, + # "travel_date": { + # "label": "Travel start date", + # "type": "date", + # "value": "2016-05-22T14:56:28.000Z" + # }, + # "fare": { + # "label": "Fare", + # "type": "decimal", + # "value": "1024.99" + # }, + # "lowest_fare_screenshot": { + # "label": "Lowest fare screenshot", + # "type": "file", + # "value": "e92h842jiu49f8..." + # }, + # "plane_ticket_invoice": { + # "label": "Plane ticket invoice PDF", + # "type": "file", + # "value": "" + # } + # }, + # "rule_violations": [ + # { + # "error_text": "Plane ticket invoice must be submitted." + # } + # ] + # }, + # { + # "id": 2, + # "completed": False, + # "title": "Hotel info", + # "html_description": "

If you used a hotel, please enter the details.

", + # "fields": { + # "total": { + # "label": "Total cost", + # "type": "decimal" + # } + # }, + # "rule_violations": [ + # ] + # } + # ] + # } return JsonResponse(data) elif request.method == 'PUT': return JsonResponse({"message": "Report submitted."}) elif request.method == 'DELETE': return JsonResponse({"message": "Deleted report {0}.".format(report_pk)}) +# change this api view again!! @api_view(['PUT']) -def section(request, report_pk, section_pk): +def section(report_pk, section_pk): ''' Update a section with new data. ''' From ae86657fcd97fa12c851c4729cea12cee1ac49ac Mon Sep 17 00:00:00 2001 From: Rupika Date: Mon, 4 Feb 2019 12:10:12 -0800 Subject: [PATCH 06/32] Deleted serializer.py and committing final changes --- back/backend/serializers.py | 66 ------------------------------------- back/backend/urls.py | 14 +++----- back/backend/views.py | 5 ++- 3 files changed, 7 insertions(+), 78 deletions(-) delete mode 100644 back/backend/serializers.py diff --git a/back/backend/serializers.py b/back/backend/serializers.py deleted file mode 100644 index 16d78e4..0000000 --- a/back/backend/serializers.py +++ /dev/null @@ -1,66 +0,0 @@ -# # Rupika Dikkala -# # January 23, 2019 -# # File contains serializers needed -# # to set up API end points -# -# from rest_framework import serializers -# from . import models -# -# # serializer for reports -# class ReportSerializer(serializers.ModelSerializer): -# # user id is foreign key -# user_id = serializers.PrimaryKeyRelatedField(many=False, read_only=True) -# -# class Meta: -# fields = ( -# 'user_id', -# 'title', -# 'date_created', -# # 'data_submitted', -# 'submitted', -# ) -# model = models.Report -# -# -# # section serializer -# class SectionSerializer(serializers.ModelSerializer): -# # report id foriegn key -# report_id = serializers.PrimaryKeyRelatedField(many=True, read_only=True) -# -# -# class Meta: -# fields = ( -# 'report_id', -# 'completed', -# 'title', -# 'html_description', -# 'number', -# ) -# model = models.Section -# -# -# class FieldSerializer(serializers.ModelSerializer): -# # section_id is foriegn key -# section_id = serializers.PrimaryKeyRelatedField(many=True, read_only=True) -# -# class Meta: -# fields = ( -# 'section_id', -# 'label', -# 'number', -# 'type', -# 'completed', -# ) -# model = models.Field -# -# -# class DataSerializer(serializers.ModelSerializer): -# field_id = serializers.PrimaryKeyRelatedField(many=False, read_only=True) -# -# -# -# -# -# -# - diff --git a/back/backend/urls.py b/back/backend/urls.py index 2ff9fcc..e0b18a6 100644 --- a/back/backend/urls.py +++ b/back/backend/urls.py @@ -5,17 +5,13 @@ from rest_framework.urlpatterns import format_suffix_patterns from . import views urlpatterns = [ - # path('print', views.get_reports), - # path('print', views.get_sections), - - - # path('report', views.report), + path('report', views.report), path('reports', views.reports), path('report/', views.report_detail), - # path('report//section/', views.section), - # path('account', views.account), - # path('account/login', views.account_login), - # path('account/logout', views.account_logout), + path('report//section/', views.section), + path('account', views.account), + path('account/login', views.account_login), + path('account/logout', views.account_logout), ] urlpatterns = format_suffix_patterns(urlpatterns) \ No newline at end of file diff --git a/back/backend/views.py b/back/backend/views.py index 4974f8c..f8f135c 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -4,7 +4,6 @@ from rest_framework.decorators import api_view from django.shortcuts import render from django.http import JsonResponse from .models import * -from .serializers import * # function that prints all the reports @@ -249,9 +248,8 @@ def report_detail(request, report_pk): elif request.method == 'DELETE': return JsonResponse({"message": "Deleted report {0}.".format(report_pk)}) -# change this api view again!! @api_view(['PUT']) -def section(report_pk, section_pk): +def section(request, report_pk, section_pk): ''' Update a section with new data. ''' @@ -264,6 +262,7 @@ def section(report_pk, section_pk): "lowest_fare_screenshot": "image", } } + return JsonResponse(data) @api_view(['POST']) From c2e3d3640cd5a4a0f1ecf6e5a39ebccb4a0b012a Mon Sep 17 00:00:00 2001 From: Rupika Date: Mon, 4 Feb 2019 17:14:29 -0800 Subject: [PATCH 07/32] removed extra comments from dummy api --- back/backend/views.py | 90 ------------------------------------------- 1 file changed, 90 deletions(-) diff --git a/back/backend/views.py b/back/backend/views.py index f8f135c..06ba04e 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -1,7 +1,4 @@ -from rest_framework import generics -from rest_framework import status from rest_framework.decorators import api_view -from django.shortcuts import render from django.http import JsonResponse from .models import * @@ -150,98 +147,11 @@ def reports(request): return JsonResponse(report_set) - # data = { - # "reports": [ - # { - # "report_pk": 1, - # "title": "2018 Portland trip", - # "date_created": "2018-05-22T14:56:28.000Z", - # "state": "created", - # "date_submitted": "0000-00-00T00:00:00.000Z" - # }, - # { - # "report_pk": 2, - # "title": "2017 Los Angeles trip", - # "date_created": "2017-05-22T14:56:28.000Z", - # "state": "submitted", - # "date_submitted": "2017-07-22T14:56:28.000Z" - # }, - # { - # "report_pk": 3, - # "title": "2017 Denver trip", - # "date_created": "2015-04-22T14:56:28.000Z", - # "state": "accepted", - # "date_submitted": "2015-06-22T14:56:28.000Z" - # } - # ] - # } - # return JsonResponse(data) @api_view(['GET', 'PUT', 'DELETE']) def report_detail(request, report_pk): if request.method == 'GET': data = get_reports(report_pk) - # data = { - # "report_pk": report_pk, - # "title": "2018 Portland trip", - # "date_created": "2018-05-22T14:56:28.000Z", - # "submitted": False, - # "date_submitted": "0000-00-00T00:00:00.000Z", - # "sections": [ - # { - # "id": 1, - # "completed": True, - # "title": "Flight Info", - # "html_description": "

Enter flight details here.

", - # "fields": { - # "international": { - # "label": "International flight", - # "type": "boolean", - # "value": True - # }, - # "travel_date": { - # "label": "Travel start date", - # "type": "date", - # "value": "2016-05-22T14:56:28.000Z" - # }, - # "fare": { - # "label": "Fare", - # "type": "decimal", - # "value": "1024.99" - # }, - # "lowest_fare_screenshot": { - # "label": "Lowest fare screenshot", - # "type": "file", - # "value": "e92h842jiu49f8..." - # }, - # "plane_ticket_invoice": { - # "label": "Plane ticket invoice PDF", - # "type": "file", - # "value": "" - # } - # }, - # "rule_violations": [ - # { - # "error_text": "Plane ticket invoice must be submitted." - # } - # ] - # }, - # { - # "id": 2, - # "completed": False, - # "title": "Hotel info", - # "html_description": "

If you used a hotel, please enter the details.

", - # "fields": { - # "total": { - # "label": "Total cost", - # "type": "decimal" - # } - # }, - # "rule_violations": [ - # ] - # } - # ] - # } return JsonResponse(data) elif request.method == 'PUT': return JsonResponse({"message": "Report submitted."}) From ba1146f9fd33404acdea7b6ce7ea386b6a1048ec Mon Sep 17 00:00:00 2001 From: Rupika Date: Mon, 4 Feb 2019 17:16:50 -0800 Subject: [PATCH 08/32] replaced old db.sqlite3 with updated one from master --- back/db.sqlite3 | Bin 53248 -> 59392 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 42abd451cc1aa0043c727d3948c91babae07e215..cb78c4ce8a1b68160cad808fed6c059b6c863fe2 100644 GIT binary patch delta 3480 zcmeHKU2Gd!6`niCPMkDtl5G-4ZE2ir(j%DI` zC6Z9%S)~IWAJxG)l1s%@WGTLqQ&(3BbX0qAsNc{|CMD0P_VJ<7j&`t8@K^XH{1&XW zBON2qb5u8AY#0^`#9^ar*DiM6?{5bS1%H8$;33?Fufq*kh6qf9r8d}c40>K_*HHt; z`h?HywCSVo!zlGft+mH%Kz#_PCuA^axasNAp+VGMR^ydO13vna4h^GrC7z8J<4w^> zQxr>)*L^BF-Kj$Zs9jc+CSnmOZjKClqhu+$t;m35p9uR6DZS*6J z{&b@s)+Ww=)N-GKFnyl@@6v|NFVIJ*%`vC;JACqzv*-*&gXJ}+^P+OfV_lhUCW%u3~QfY@C0KvG1$Rk2ZzsC%@(Vj z(=fNyi8+V4E{_nyS{AbG0^=K{17(b0vx74q~D;!bU%5O%SbDK^^X75K0P&X&bhM^48!0E z85JTVL<@tlCBj z+kxt$=x@`VR9EfDdx)-e-ue4sBAlY=56}&2YHQ23aqXN=FWk^O(@P3hD8zAM1>+*N zEa#P6GGmSx_&l?!n9Hg!G^GmZAP!fZRmqi7rL>zDaj+_+Q)wxk&515W4Trqz;dGD* z<2h9dO=l(7lGU5FrU2iVO_d~UD}}MW zq`Wr06ju4hj5E1y+-!9w!>)`DU z9-rYk-exvmI|mz$gspSMM6y!J;&iT@h%4(AzO-()6cce3Tk_@Ps+gP0gsbkVFC=A! zkbg~ZWmR7wjHOVpBD&nXfZeRV_S!kr$dmTTJyY#Z?;b-P0Jkal81BJsxJ^#YB5a%j0m*C05~C(7xni<}E6WwT zwWzG{aV1JN@=76R(bqvQN;cF%FWSPomqBQg1;3?F_h00q2Dow`pjPcE~h3qgf68-bzF}9-_P0=z@Pr|=H^ z48B4(V+j^df)j0DyY+LwLlYKkW_kTyHS5^D+hMN%BkejsR$7&&x;FRo@9X>8&;ts70k=Se9{Tt6 zcj!Fbg&vSV@1WsXV;kk{G%ldFo#Zi1HZnWR9N}0Sk2&q_o2Jesd3Ci?SW$)+uUuJd zqibCsK0!wg*O%gRLi(JL{_lj;hi?B=*MjH|NHIjV@_RHXh4c-^dJ!WDp)e;_W4x5} zuZOGIjNnS8#gLdH)eGUy>5LR`uZe*mFS_a#i$K`jTb0rWF#G>r3K_Bu>K9Z^d^a|@ z@6xJ&NRWpnjVH}QF1o*g_RoDM*j<5Di>4$ delta 1008 zcmah`UuauZ7(eHHNpss~%`NScIZMq-*KTYv_uiyQv*|50WJ3@Iy=dqd3>_#=nBu^0(#hDHqQw{AJq?JAJ$N{W?|i@S zobUY3@3;ITEH~iV^Suf}$j#QjBf4?ag_X}P8$ z?w~;~nV8{u7~PGzbTJjbkWJ@Pu!C&948>2O=Dir4IHe_unNqxv&CDk%*;29GPj7Ya z<2u>PeFiu}x4RE@b;2nGJMcaHqVwia*l1YkDa)p{6T%4ogokh!K7sdP73LrgVZC=i z02=PQ3B!1Vn)*ZZ0Qa*#viDaj41m zY0x)TR)a+;Tnc0=fnm?tiP?m6vMR(bxTm}x_qo@m)Qb~B<+Lm>DicSlPR%n>5fYWW z&;K%&TpJd_b4+p{bNgNtq;b*b)_-zI0kFblYFcnGdLhs+zqw{$2&JawT_g@VU76$f z4ziBm3#h{h*hB7-b;c}->BV=Obl+Pwef?^+w~G)9A|Db9v9N!A)K#~Sn`~!9To2Ou zO;1NWUdpEq(n!-vZ*MwJx6>i}p`mhmW>?&JHpS-9VJ7aEHc`ZD{z@X5Pd{Z#`_8k7 zi~hixzS1xn+Xv_y${2mS;m|G3zxQwiuOjj_US)h2@cAppiBVoP`m5#fjHjAg5WLk) z!kwA%iiKJ^nJ(phi-lTJszd@gS0pf*RSRJ)7C4cUwaHmUQ#4hY&M85*J1YyZg1i`s zh6FV#3-Zz#QHfIf*1*_FK`y*1#eyfrn5K$yAtb~C{v}0H7u2Q9SWFAm)F`WHF-_J~ zx2mZw7U|s9emq6r*_wIIYyZz9w;+04SB~R0XZpBh*MI+fKjsLu5Ntz>+4C_R90nQx z-+u_*ZjG3kJ%~q$hs??)y{CbR0U>-&?`uXeo!$Jv+{MHva0kH?xWjt4;Dtf(V@VKw z4ncB=&oCqUliNdv0W+CK@EC5wdoT}C5Wr0SAa_ZVERks@yNBr0-+XH9=LnDBJGcr8 g^pi*A1}PGrm4CyQl}lceZFCf`dE1`r{Jp>MKcLhqK>z>% From 84aa01e008bf93f3fb52b942c885a66c2b68be61 Mon Sep 17 00:00:00 2001 From: Rupika Date: Mon, 4 Feb 2019 18:02:32 -0800 Subject: [PATCH 09/32] 1) added a user in the admin to change the user_id in report -- updated database! 2) removed double dictionary for fields in view.py --- back/backend/views.py | 8 +++++--- back/db.sqlite3 | Bin 59392 -> 59392 bytes 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/back/backend/views.py b/back/backend/views.py index 4d1689b..21ab7d5 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -50,11 +50,13 @@ def get_fields(s_id): queryset = Field.objects.filter(section_id=s_id) # queryset = Field.objects.all() for i in queryset: - data = {i.label: { + data = { + "field_name": "TODO", "label": i.label, "type": i.type, - "value": i.number, - }} + "number": i.number, + "value": "get_value", + } # append the fields to array # use copy() to avoid overwriting field_set["fields"].append(data.copy()) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index cb78c4ce8a1b68160cad808fed6c059b6c863fe2..7c7ffb7bd3ce444e322cde768b99da9a7a1dc08c 100644 GIT binary patch delta 1320 zcma)5TWB0r7@jl#-e%LJ7B@CqFS!sgB_^5sWowXVnrzz6#H8EHZi#VrXEr;tm)T~M zZZ>N$jS*?VYTQ>rP|*hwtb+t0An22VP^DBK?2GoL)zT;NArE?HlN6y3^)Tl@^Pm6x zm-Bz$S-l3U*WjJUTQ3s?5yMl$6K(WK=vaMzP1c)#KprzsJ*qdHAIaN<#gW2va^+(&I)2L!_s*4W=h8sP9bS$ zmZqz{A}iEmfIG;0aOUun|B5G?(u`qMxu}>;CHwQKf{l(0{7rH~Hd8=Dne0%QsJ4L*Wz;SI>*6bTr93P#Xg_Zg+x{boA_nqx#E@Su4Y1Ci$i+Wqir zecz!L)JMQ~a0N7okT=PX$rAYp+Cpon57Q@%*t1cJ7}@`H5>fXv?cglXF-97c7>Sl8 zX3UzeEObqqWoLe&@&22K;vO$%Eu&{T5s-;F#`DEgB z5&PAW_H1b5imLrWPAh7bR#a=6owGDMQ`4-*iL24^rHK+fym#FP(OEm< zZ{Fge=-;{FN8L?u|BIeS#oZy|Rm6n22aSK8@dprW60nK&&*0=Z^39AOi8ZoHS~s&2 zs~9pPWLaI870KjSAZlY&r1st0?~Q`ORwc<4bVf>Q9H18?}|oB7^+?|qFGG*)nT z|Be|#NL<2}!0eDsXC7ae@9wJ*5BgQq(Z)k0aUT6JF^4N6;#cAJ`wqFMeS5>9pclim zTF#fsW7%rCGFj}z4DU&|CzBR+->pFpV@m|**pi5N7MZ)mF9ys3jmLE!H~5HcTDD`j z+_)1k2DlM7I~OCC8Rfbz-WWXC!>~c{U2a6|Os>LPof@0Umx>c*v2ikVWOoQPf=^h( zJG{nKY+~K*n;sB>0||&){kDP-nr?UFsLY&&XkM=ev4wB)v<{yNN*Pl?z3j=oue&G{ z8;|xV^D9bkPsa?*5qv;Ps-BbYQy3h?C{0g~SG9@pTCp--<+aN-$FAf`(R?lw<5p?1 zXo=ZYS@8o41Rt@0=eQ|rs|bgYpj^|PVT}*#v26xe+|;Au{}?UZ9Cn2(mTy zfL&s}v@Ly`r=tBT+0{kaGGWUy@stf+JEp3mH`K&G8~VJe(#T&wN`allB%%_Q>~a(C zkAq%@mW&s1<^)wzvgdrp&~@9)7Bt;3(}h^nw9~whbqbcPIgV}`dBe`-vcI)y+lQ-L lQEs!2nM9F>zLmr;ar`h+-v6cjQ@ceR$r6(cU!eXP*-xL|xaa@? From 99b5bd1ca9d5c3e0d4a567555acc0426573198dc Mon Sep 17 00:00:00 2001 From: kououken Date: Mon, 4 Feb 2019 18:29:05 -0800 Subject: [PATCH 10/32] Configure registration app --- back/Pipfile | 3 ++- back/reimbursinator/settings.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/back/Pipfile b/back/Pipfile index 54943ec..c996bfc 100644 --- a/back/Pipfile +++ b/back/Pipfile @@ -9,8 +9,9 @@ verify_ssl = true django = "==2.1.5" django-cors-headers = "==2.4.0" djangorestframework = "==3.8.2" -gunicorn = "==19.6.0" django-rest-auth = "==0.9.3" +django-allauth = "==0.37.1" +gunicorn = "==19.6.0" [requires] python_version = "3.5" diff --git a/back/reimbursinator/settings.py b/back/reimbursinator/settings.py index 6fb5556..503958c 100644 --- a/back/reimbursinator/settings.py +++ b/back/reimbursinator/settings.py @@ -39,10 +39,14 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django.contrib.sites', # 3rd party 'rest_framework', 'rest_framework.authtoken', + 'allauth', + 'allauth.account', 'rest_auth', + 'rest_auth.registration', 'corsheaders', # local 'users', @@ -149,3 +153,9 @@ USE_TZ = True # https://docs.djangoproject.com/en/2.1/howto/static-files/ STATIC_URL = '/static/' + +# Email Config + +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + +SITE_ID = 1 From efa342dc7fe4054d69c5aefdbd42823ded9e275b Mon Sep 17 00:00:00 2001 From: Preston Doman Date: Tue, 5 Feb 2019 01:05:04 -0800 Subject: [PATCH 11/32] Fix token authentication --- front/static/js/login.js | 5 +++-- front/static/js/logout.js | 6 +++--- front/static/js/viewHistory.js | 8 +++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/front/static/js/login.js b/front/static/js/login.js index 8269c99..7be086e 100644 --- a/front/static/js/login.js +++ b/front/static/js/login.js @@ -10,9 +10,10 @@ function postToLoginEndpoint(event) { "username" : this.elements.username.value, "password" : this.elements.password.value } - const url = "https://reqres.in/api/login" // mock api service + const url = "https://" + window.location.hostname + ":8444/api/v1/account/login/"; const xhr = new XMLHttpRequest(); + console.log("Attempting a connection to the following endpoint: " + url); console.log("User credentials:\n" + JSON.stringify(credentials)); xhr.open("POST", url, true); @@ -22,7 +23,7 @@ function postToLoginEndpoint(event) { if (this.status === 200) { console.log("LOGIN SUCCESS!"); console.log("Server response:\n" + this.response); - token = JSON.parse(this.response).token; + token = JSON.parse(this.response).key; localStorage.setItem("token", token); window.location.replace("home.html"); } else { diff --git a/front/static/js/logout.js b/front/static/js/logout.js index c10c381..b3bef0d 100644 --- a/front/static/js/logout.js +++ b/front/static/js/logout.js @@ -2,18 +2,18 @@ function postToLogoutEndpoint(event) { event.preventDefault(); const token = localStorage.getItem("token"); - const url = "https://reqres.in/api/logout" // mock api service + const url = "https://" + window.location.hostname + ":8444/api/v1/account/logout/"; const xhr = new XMLHttpRequest(); xhr.open("POST", url, true); - xhr.setRequestHeader("Authorization", "Token " + token); + xhr.setRequestHeader("Authorization", "Bearer " + token); xhr.onreadystatechange = function() { if (this.readyState === 4) { if (this.status === 200) { console.log("LOGOUT SUCCESS!"); console.log("Server response:\n" + this.response); localStorage.removeItem("token"); - window.location.replace("index.html"); + window.location.replace("/"); } else { console.error("LOGOUT FAILURE!"); console.error("Server status: " + this.status); diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index 7e7a88c..82c2f4d 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -10,7 +10,9 @@ function getDataFromEndpoint(url, callback) { console.log("Attempting a connection to the following endpoint: " + url); + xhr.open("GET", url, true); + xhr.setRequestHeader("Authorization", "Bearer " + token); xhr.onreadystatechange = function() { if (this.readyState === 4) { if (this.status === 200) { @@ -222,7 +224,7 @@ function displayListOfReports(parsedData) { for (let i = 0; i < reports.length; i++) { let title = reports[i].title; let dateCreated = new Date(reports[i].date_created).toLocaleDateString("en-US"); - let state = reports[i].state; + let submitted = reports[i].submitted; let dateSubmitted; let rid = reports[i].report_pk; @@ -231,7 +233,7 @@ function displayListOfReports(parsedData) { bodyRow.insertCell(1).innerHTML = dateCreated; let stateCell = bodyRow.insertCell(2); - stateCell.innerHTML = state; + stateCell.innerHTML = submitted; stateCell.classList.add("d-none", "d-lg-table-cell"); // Column visible only on large displays // Create edit/view button @@ -240,7 +242,7 @@ function displayListOfReports(parsedData) { actionButton.setAttribute("data-rid", rid); actionButton.classList.add("btn"); - if (state === "created") { + if (submitted === false) { // Edit button dateSubmitted = "TBD"; actionButton.classList.add("btn-primary", "edit-report-button"); // Add event listener class From 5d12cb64e4afe3eb53639e8465ffe4b7f46e5b37 Mon Sep 17 00:00:00 2001 From: Preston Doman Date: Tue, 5 Feb 2019 10:12:30 -0800 Subject: [PATCH 12/32] Remove error message display --- front/static/js/login.js | 6 ------ front/static/js/viewHistory.js | 6 +++--- front/static/login.html | 1 - 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/front/static/js/login.js b/front/static/js/login.js index 7be086e..cdef5f4 100644 --- a/front/static/js/login.js +++ b/front/static/js/login.js @@ -1,8 +1,3 @@ -function displayErrorMessage(errorMessage) { - const errorReport = document.querySelector("#errorReport"); - errorReport.innerHTML = JSON.parse(errorMessage).error; -} - function postToLoginEndpoint(event) { event.preventDefault(); @@ -30,7 +25,6 @@ function postToLoginEndpoint(event) { console.error("LOGIN FAILURE!"); console.error("Server status: " + this.status); console.error("Server response:\n" + this.response); - displayErrorMessage(this.response); } } }; diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index 82c2f4d..4b2899b 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -224,7 +224,7 @@ function displayListOfReports(parsedData) { for (let i = 0; i < reports.length; i++) { let title = reports[i].title; let dateCreated = new Date(reports[i].date_created).toLocaleDateString("en-US"); - let submitted = reports[i].submitted; + let state = reports[i].submitted; let dateSubmitted; let rid = reports[i].report_pk; @@ -233,7 +233,7 @@ function displayListOfReports(parsedData) { bodyRow.insertCell(1).innerHTML = dateCreated; let stateCell = bodyRow.insertCell(2); - stateCell.innerHTML = submitted; + stateCell.innerHTML = state; stateCell.classList.add("d-none", "d-lg-table-cell"); // Column visible only on large displays // Create edit/view button @@ -242,7 +242,7 @@ function displayListOfReports(parsedData) { actionButton.setAttribute("data-rid", rid); actionButton.classList.add("btn"); - if (submitted === false) { + if (state === false) { // Edit button dateSubmitted = "TBD"; actionButton.classList.add("btn-primary", "edit-report-button"); // Add event listener class diff --git a/front/static/login.html b/front/static/login.html index 5c60531..03938ea 100644 --- a/front/static/login.html +++ b/front/static/login.html @@ -41,7 +41,6 @@ -

From 15d50a7c50f04b8b451cdcf2904d030d24bde8fc Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 5 Feb 2019 11:28:58 -0800 Subject: [PATCH 13/32] Display error message when login fails --- front/static/js/login.js | 1 + front/static/login.html | 1 + 2 files changed, 2 insertions(+) diff --git a/front/static/js/login.js b/front/static/js/login.js index cdef5f4..20b411d 100644 --- a/front/static/js/login.js +++ b/front/static/js/login.js @@ -22,6 +22,7 @@ function postToLoginEndpoint(event) { localStorage.setItem("token", token); window.location.replace("home.html"); } else { + document.getElementById("errorLogin").innerHTML = "Incorrect user name or password"; console.error("LOGIN FAILURE!"); console.error("Server status: " + this.status); console.error("Server response:\n" + this.response); diff --git a/front/static/login.html b/front/static/login.html index 03938ea..9a8af2f 100644 --- a/front/static/login.html +++ b/front/static/login.html @@ -31,6 +31,7 @@ +

From 1ec02e1d224142570948a60136230188307a05df Mon Sep 17 00:00:00 2001 From: kououken Date: Tue, 5 Feb 2019 12:48:49 -0800 Subject: [PATCH 14/32] Added report_pk to reports api endpoint> --- back/backend/views.py | 1 + back/db.sqlite3 | Bin 59392 -> 59392 bytes 2 files changed, 1 insertion(+) diff --git a/back/backend/views.py b/back/backend/views.py index 21ab7d5..70e3f79 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -139,6 +139,7 @@ def reports(request): queryset = Report.objects.all() for i in queryset: data = { + "report_pk": i.id, "title": i.title, "date_created": i.date_created, "submitted": i.submitted, diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 7c7ffb7bd3ce444e322cde768b99da9a7a1dc08c..2a1a5530382cc2affd37e357a256cd3fa46289dd 100644 GIT binary patch delta 325 zcmZp;z}#?wd4e=!??f4A#@>wyhmH7+46IBntc*DD zu|<+uRfXA?(a5N%*gVZVJ2@*mwKT2BG%-0VrOYt7)GRA4$09vHlYO(t_B|{DY|QQq z%#WCtFdt@aWlm#u-z+F&%se@5KfeIN7E22w69e|mY5V7iOlG;@63x!)+rsKd$O2!N zK+~vjuiVJ0NK?NMM*}~Xpqxk}znsYMu&l_cY*XJ5r<^F4M`WXcRO^Y=04M{ffbq_R( Z3JEmv4W8_?QC-kd0nOQ)Tdvj!0Ra8DW?%pS delta 106 zcmV-w0G0oM&;x+b1CSd5ijf>c0gAC;!!i#rF*-9bIxsmdG&D9aH88U>Gtz(r1p`O` zvkJ5s1CgL7vq-nR1P%oQW&i`?1Ed4P1BC--vk@Fr1CvL;53_Z@j}!<30fYbo!U2S{ MAqaQ@vxL=r673fubN~PV From 72ab00dd503277ed4d93ada26ca3a17ff88e988c Mon Sep 17 00:00:00 2001 From: kououken Date: Tue, 5 Feb 2019 14:56:48 -0800 Subject: [PATCH 15/32] User registration endpoint working. --- back/Pipfile.lock | 72 +++++++++++++++++++++++++++++++++++- back/db.sqlite3 | Bin 59392 -> 71680 bytes back/reimbursinator/urls.py | 1 + 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/back/Pipfile.lock b/back/Pipfile.lock index e493330..a6ed173 100644 --- a/back/Pipfile.lock +++ b/back/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d3bf402a934e168cbdc04022effcdb9ff8d4fde5b83d79bb388ad2a4c547894a" + "sha256": "b1fc6b06ec8daa4efd9573865bc6c1732ae9354309e036bfe3ce0ab76b1a3bcd" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,27 @@ ] }, "default": { + "certifi": { + "hashes": [ + "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", + "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033" + ], + "version": "==2018.11.29" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "defusedxml": { + "hashes": [ + "sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4", + "sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20" + ], + "version": "==0.5.0" + }, "django": { "hashes": [ "sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8", @@ -24,6 +45,13 @@ "index": "pypi", "version": "==2.1.5" }, + "django-allauth": { + "hashes": [ + "sha256:02175aa1c2ddfd935a54011d1196d70c976647fc46f603f8b8758fc395b9d277" + ], + "index": "pypi", + "version": "==0.37.1" + }, "django-cors-headers": { "hashes": [ "sha256:5545009c9b233ea7e70da7dbab7cb1c12afa01279895086f98ec243d7eab46fa", @@ -55,6 +83,27 @@ "index": "pypi", "version": "==19.6.0" }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "oauthlib": { + "hashes": [ + "sha256:0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298", + "sha256:3e1e14f6cde7e5475128d30e97edc3bfb4dc857cb884d8714ec161fdbb3b358e" + ], + "version": "==3.0.1" + }, + "python3-openid": { + "hashes": [ + "sha256:0086da6b6ef3161cfe50fb1ee5cceaf2cda1700019fda03c2c5c440ca6abe4fa", + "sha256:628d365d687e12da12d02c6691170f4451db28d6d68d050007e4a40065868502" + ], + "version": "==3.1.0" + }, "pytz": { "hashes": [ "sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9", @@ -62,12 +111,33 @@ ], "version": "==2018.9" }, + "requests": { + "hashes": [ + "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", + "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + ], + "version": "==2.21.0" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57", + "sha256:d3ed0c8f2e3bbc6b344fa63d6f933745ab394469da38db16bdddb461c7e25140" + ], + "version": "==1.2.0" + }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" ], "version": "==1.12.0" + }, + "urllib3": { + "hashes": [ + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + ], + "version": "==1.24.1" } }, "develop": {} diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 2a1a5530382cc2affd37e357a256cd3fa46289dd..43dd0a70ac73808220ed2638b5dc6c8b5c5a8e6c 100644 GIT binary patch delta 4832 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 PvA0XC{*EdMw1)i)68}4Y diff --git a/back/reimbursinator/urls.py b/back/reimbursinator/urls.py index 62397e8..b39c33f 100644 --- a/back/reimbursinator/urls.py +++ b/back/reimbursinator/urls.py @@ -13,5 +13,6 @@ urlpatterns = [ path('admin/', admin.site.urls), path('api/v1/', include("backend.urls")), path('api/v1/account/', include('rest_auth.urls')), + path('api/v1/account/register/', include('rest_auth.registration.urls')), path('api-auth/', include('rest_framework.urls')), ] From d4c972e5d95f650ec519c68804d2d6555544723d Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 5 Feb 2019 15:31:55 -0800 Subject: [PATCH 16/32] successfully getting the correct report. still to do print report to modal --- front/static/js/viewHistory.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index 4b2899b..802da82 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -252,7 +252,7 @@ function displayListOfReports(parsedData) { } else { // View button dateSubmitted = new Date(reports[i].date_submitted).toLocaleDateString("en-US"); - actionButton.classList.add("btn-success"); + actionButton.classList.add("btn-success", "view-report-button"); actionButton.innerHTML = "View"; } @@ -266,6 +266,11 @@ function displayListOfReports(parsedData) { } } +function displayReport(parsedData){ + window.alert(parsedData.date_created); //Able to get the correct report ID now just needs to display the + //report as an modual +} + document.addEventListener("DOMContentLoaded", function(event) { const url = getEndpointDomain() + "api/v1/reports"; getDataFromEndpoint(url, displayListOfReports); @@ -277,6 +282,11 @@ document.addEventListener("click", function(event) { const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid; getDataFromEndpoint(url, createEditReportForm); } - + if(event.target && event.target.classList.contains("view-report-button")) + { + console.log("View button clicked"); + const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid; + getDataFromEndpoint(url, displayReport); + } // TODO: Add view report }); From 6e8478cf67766efea942ca7849aaff3c6f9c94e5 Mon Sep 17 00:00:00 2001 From: kououken Date: Tue, 5 Feb 2019 15:38:34 -0800 Subject: [PATCH 17/32] Changed to email instead of username, added first and last name. --- back/db.sqlite3 | Bin 71680 -> 89088 bytes back/reimbursinator/settings.py | 12 ++++++++ back/reimbursinator/urls.py | 1 + back/users/serializers.py | 47 ++++++++++++++++++++++++++++++++ back/users/views.py | 2 -- 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 back/users/serializers.py diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 43dd0a70ac73808220ed2638b5dc6c8b5c5a8e6c..85281da711c907b2d1d5a7697864a5705948c739 100644 GIT binary patch delta 7261 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 LS&#Yagu;ITceN8& delta 1813 zcma)6ZERCj7(VB`cWt+|qk};i45%HEjj`_D+uq)81STKdDBEq>H{CL7*LLf7=h`tC zG1+jMXyON)7({;<|496yXs*DBd>H?s85jkOfHdFwsIM@g0;Ust=46DEn2jK?1qZXI_LX1TVpo~zbM$<{61{(O$0)rp>QUX3)?_u z5Sf7j_!&NfZ$O48VF;du_uw#8Kobl00#Rp*7U7i!avQ-<@HKo2@4{;^0Z)M+wu1xK zKt8$69M2Q=_QH}XWr9_z;+KskSegNYHViwCE35wAM<3z&q6q;&XTb zFVxxjI-a-YJRMH;3!7MCr7sft)8V6CYWMr|}Uy zjAix<6ISIHrye(Ipd3LtT!n3Lf=MOG7#6_l)u3Q0X>*E$gNbZV7<7z;osldr4)u$B zYsE}FD2?#6@x*B(hi4EBkTl_$(S(|)z{#4HW{oLaPmPC`(p{4VYP_dg>rW>_e&JDa z@aMMHBZS*b_4Rn7hF+g7T{Q>(tG7%S+_B`%`B34GWSLW!#k@N(6pRFhDrBkB?D4jn zJsr)><_?d$rNc#ocMhtzPnHnSK%=TXwFBnQ$8HsD4x40C!)M>rFDt|q2+qMv;DHkI zEqR-yh!LN{`*8)USOHcmrmkuz_xaWyZJsibx9Ptsq$C?+KCw08>1v4kMqMLHY(Vn0 zw@99?F2URAvin9m6N=an=}vaXlvpC_-P#)W(d(BM(On;CF;CB2%(U4&Te}lJQQ7Nl zZ;dFU9d^%Xcg!;yw|PYOsFLj1qjYsL@)n`H%PlCQab9U}vAI+HUlJ8+?@M$(*NIDG zM33P jxJoP!WM`rzdcSh0Z2~oQ&#w$jbwaIrY~YI=wNC0G&bT3@HOESkW+DIBTKGY|Ya8Ev>Fi z?Jl#Mm4Bz%!qnB+sxkFQ59oBIN+)+=`ov^g8RI_N$aLHzVH8cF7O!@EtygR6s>kC^ zbmQzs&7Az|>C>~y!a37ouCU~8On)?FsZ_1^F6%THZX&qJBK!`_C0K)W`FIVNYvU(! zlQo!5=I%law-DT#%R?~2n*6^x7_b55Au}Q$ks*A68JF4fz@RmEk87k(jmcfk@-QE| zRfvmQ+5RWv>)W-a>T0~dG8^bigde!{=c0Xhy?(wp?VC0?yUdn{w{vYqKfb$y?yf5~ zO8ou)svI}B(Ur4HScPBEJffao&ARY$J?1zl!$%KkjkuO|QW~E)T8ukL0YDtV6ub^` NmVPfBiktAOzXP4Y3AX?M diff --git a/back/reimbursinator/settings.py b/back/reimbursinator/settings.py index 503958c..8725757 100644 --- a/back/reimbursinator/settings.py +++ b/back/reimbursinator/settings.py @@ -45,6 +45,7 @@ INSTALLED_APPS = [ 'rest_framework.authtoken', 'allauth', 'allauth.account', + 'allauth.socialaccount', 'rest_auth', 'rest_auth.registration', 'corsheaders', @@ -159,3 +160,14 @@ STATIC_URL = '/static/' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' SITE_ID = 1 + +# Registration + +ACCOUNT_USER_MODEL_USERNAME_FIELD = 'username' +ACCOUNT_EMAIL_REQUIRED = True +ACCOUNT_USERNAME_REQUIRED = False +ACCOUNT_AUTHENTICATION_METHOD = 'email' + +REST_AUTH_REGISTER_SERIALIZERS = { + 'REGISTER_SERIALIZER': 'users.serializers.RegisterSerializer', +} diff --git a/back/reimbursinator/urls.py b/back/reimbursinator/urls.py index b39c33f..7a33b6d 100644 --- a/back/reimbursinator/urls.py +++ b/back/reimbursinator/urls.py @@ -14,5 +14,6 @@ urlpatterns = [ path('api/v1/', include("backend.urls")), path('api/v1/account/', include('rest_auth.urls')), path('api/v1/account/register/', include('rest_auth.registration.urls')), + # path('api/v1/account/register/', NameRegistrationView.as_view()), path('api-auth/', include('rest_framework.urls')), ] diff --git a/back/users/serializers.py b/back/users/serializers.py new file mode 100644 index 0000000..91416a4 --- /dev/null +++ b/back/users/serializers.py @@ -0,0 +1,47 @@ +from rest_framework import serializers +from allauth.account import app_settings as allauth_settings +from allauth.utils import email_address_exists +from allauth.account.adapter import get_adapter +from allauth.account.utils import setup_user_email +from django.utils.translation import gettext as _ + +class RegisterSerializer(serializers.Serializer): + email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED) + first_name = serializers.CharField(required=True, write_only=True) + last_name = serializers.CharField(required=True, write_only=True) + password1 = serializers.CharField(required=True, write_only=True) + password2 = serializers.CharField(required=True, write_only=True) + + def validate_email(self, email): + email = get_adapter().clean_email(email) + if allauth_settings.UNIQUE_EMAIL: + if email and email_address_exists(email): + raise serializers.ValidationError( + _("A user is already registered with this e-mail address.")) + return email + + def validate_password1(self, password): + return get_adapter().clean_password(password) + + def validate(self, data): + if data['password1'] != data['password2']: + raise serializers.ValidationError( + _("The two password fields didn't match.")) + return data + + def get_cleaned_data(self): + return { + 'first_name': self.validated_data.get('first_name', ''), + 'last_name': self.validated_data.get('last_name', ''), + 'password1': self.validated_data.get('password1', ''), + 'email': self.validated_data.get('email', ''), + } + + def save(self, request): + adapter = get_adapter() + user = adapter.new_user(request) + self.cleaned_data = self.get_cleaned_data() + adapter.save_user(request, user, self) + setup_user_email(request, user, []) + user.save() + return user diff --git a/back/users/views.py b/back/users/views.py index 91ea44a..2536b37 100644 --- a/back/users/views.py +++ b/back/users/views.py @@ -1,3 +1 @@ from django.shortcuts import render - -# Create your views here. From bdddb3cc033d613b2cd0aafb71b8223bdfc56b64 Mon Sep 17 00:00:00 2001 From: kououken Date: Tue, 5 Feb 2019 15:49:03 -0800 Subject: [PATCH 18/32] Changed username frank to frank@frank.com. Password is still frank12345 --- back/db.sqlite3 | Bin 89088 -> 89088 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 85281da711c907b2d1d5a7697864a5705948c739..1b759a475639ad1b2f16c066053118c728aac9a2 100644 GIT binary patch delta 601 zcmZqJ!P>Bcb%HeSMFs|ja42S+sA0}{abp4tH>3RKRPH${+)O(em>Js`m?Ih6HuD%% zF$y%AF!3=oYC3Xgi_2JEx8S8?!P4^Bran=IzYN%#)aNftvZ5RaBUL z8OzK}jV;TJ3-Sx|&8o6;GBS*pp{1^Yk*lbMMGOh}t(nTZXFbzC)1(`51>u}vC5 zQw_Ma4lV@2U*IC#MOv^3BE_}f&ZXNfTq&drC${bc7vJH2=icve4!5&s>FilvOgaw< zf>=8Z)9y8aJnXHT?c@y3+245V#s!!H1gNHc>|oj?o!-ziI#VqphLsi=w7~GQi1Q=K z&mtP}ynsZb+Zw}!f^LammXdjOx$=3$g$#|#J zX|)9jT}GODXWHb_572{A#_tvVh^JW*`B))e*Ds(ey2_Ou9PeiZn)UJ$$Kx;D;`kr! z@ST94aD*MvPjIPVHME@@IzSl*+i;aLR&bM>ja(gUFhSxUE9d8724tOT1@PFE4Y2&E zZ#I~cPIZRNRnSY%UXPG4Fgg%k7+}}uBfx{_w)s&DL<#r?QRu@?#%wT~$rryWluM{80BN695yd57gkzK;{ z(ST*0HH+&{Z%`JwYYG0ZuYy)NwY`ee;u0^f#fu8MT~Z=<%dyD)QY@U@mJ@1IEhZT` zyyR69@eLWt23Hewr8hyg^y6Mbe}_Y3((sF%`g^ie_iN`dHcuVH?j4FG`__BpFZd0A Ck-3rp From d683ea8839495650e6a4631489884629aec4f398 Mon Sep 17 00:00:00 2001 From: kououken Date: Wed, 6 Feb 2019 13:22:40 -0800 Subject: [PATCH 19/32] Fixed user authentication backend to allow login with email. --- back/db.sqlite3 | Bin 89088 -> 89088 bytes back/reimbursinator/settings.py | 9 +++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 1b759a475639ad1b2f16c066053118c728aac9a2..8074d09696b7ab103c40188a656433376bef08ba 100644 GIT binary patch delta 1175 zcma)5U2NM_6t;bmI!=GmrVSgTgETEa8*RAP|87+=Z%wWB)GEN$x432WE2 z%{0-Bkv<`T{Ln|9c%8HwkqLDm?Wx++KunVWF$p0M5~_GWn%Kj{bp_H;CxLYQ`Cj|; zIp25g@%jz_`VIew&(M!P>ODa}y8iYTL7H`*YfT)8^>8pmFE14rm) ztf;D>5*29@rDF7W)y|XMF>=KVReRqjNM_>-(o{)y8o24BDCz@8=QqOjj(Qt-La9I` za`?pnCpdlhDJRd54xSc`9AQC{RrhNF z^>qA90o-BW0o;LI*mXNkegoa4K1BtH*kAx6dtC+h!BqPo#6WV`)mK|UhY^t6uHIjn zupelei|t|G9!A}XOE-Oln{n86!p*^(kRjYw2>F1cV;=N*5OrtY`vm#>;UqNO&QA|O zv>=vpYgJ3OD`mbatSA_-u9WR%RV-WObE^H0JJDzr!Y<%9dPg&Wq<7LAdFD0#{W%6gs$qBN`7$|ES zYpL`kGSdb!YG-gV?L_bON(p4xr}^we0%t7~8}=m1j_I`|Z?2lPIVo#Ru9#`^#>!fT zWs0U{3gqsbzjug!!|A-6f0C7}ci(5&hu&dOGU?h6;Ou_a*5Y+G$Zmaq0ZwSRD9Bn- zIfn{zF)s_6$ZI*NAc{pv%;&skSQb>2d%~2(HAzx6A?P;m{{ch)HxctP%y7=l`!8+% z^e50k_u((0gZ|%O8@7qQYp}TubbO$vCCs)^0gmnuJ~rt=Z<5G7!|$*IJB0o@Z0@l1 z3*jyZK|lQ%ll?3}`(A7FF}EmaK$h8MZV~zxlQ|mWD7~w@o#yC$jwCHEs#wxwj7TaD ztiB+nha&aX{bV$Z<+#FYq9O|3ui|{XacJ|$41I89Fd8e`x%q|I%;n279CI{E>V+cv a>tStJ;NudOu_9>s`Go}znvD!y^Zf;2dqN8U delta 786 zcma)4OHUI~6u!5o(+=-~yo@AmA_@jt=Ka7BTOPJb2@5f%3nN3Bu@!3RgG!4FR4iM~ zEcgZPjERh~Xh65b6&Q7+kqwE7iL6YBuDsKo#zgbwo}7I5%gJ{hE1T5HCiUP1-h0?J zg7=8%^<@V3@~A1~(gZ0=foF_%xL?3}ii>(;s(Um(C`1TkE8454Y$!@L>Q zvRdL&HKdaHM9$8F)fkAUQyjypeunciqL1STd0~)K0+OtVs)P{kM|aL3x~JeS@u|F$nH*S(go;A(;(%Hj4XLUaRpbld@#sh1nATz8aSZ{fzwecGQ*hO#zyKn#pmM8KKj?vIo9S73Qvg~19hZ#xNNnC=yu@quOBd&E!?sK80f^Q;4W1xe)90>6;Xq@~i0`9zW{ zhzUVvZxxGrHkDko!j*cug;njz3CbWZ2SkSDS>DoL@3opir>FPsSvNJYN`?Me>FWnK zZu+y#>ihc+_aP7u34?12kl@VS}mcG6Cv2KLF6xCeaDSYw-CDJHzho$u`}wzK<>Cqgtwtm IzJg26Un7R*n*aa+ diff --git a/back/reimbursinator/settings.py b/back/reimbursinator/settings.py index 8725757..86f1b58 100644 --- a/back/reimbursinator/settings.py +++ b/back/reimbursinator/settings.py @@ -163,11 +163,16 @@ SITE_ID = 1 # Registration -ACCOUNT_USER_MODEL_USERNAME_FIELD = 'username' +#ACCOUNT_USER_MODEL_USERNAME_FIELD = 'email' ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_USERNAME_REQUIRED = False ACCOUNT_AUTHENTICATION_METHOD = 'email' REST_AUTH_REGISTER_SERIALIZERS = { - 'REGISTER_SERIALIZER': 'users.serializers.RegisterSerializer', + 'REGISTER_SERIALIZER': 'users.serializers.RegisterSerializer', } + +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.ModelBackend', + 'allauth.account.auth_backends.AuthenticationBackend', +) From 10c2a3e1500366462db159f0817732d6de1159ae Mon Sep 17 00:00:00 2001 From: Preston Doman Date: Wed, 6 Feb 2019 15:31:15 -0800 Subject: [PATCH 20/32] Add frontend registration functionality --- front/static/edit_report.html | 2 +- front/static/home.html | 2 +- front/static/index.html | 2 +- front/static/js/login.js | 2 +- front/static/js/signupPage.js | 74 ++++++++++++++++++++++++++++------- front/static/login.html | 6 +-- front/static/new_report.html | 2 +- front/static/signup.html | 23 ++++++----- 8 files changed, 80 insertions(+), 33 deletions(-) diff --git a/front/static/edit_report.html b/front/static/edit_report.html index 80d39df..474746f 100644 --- a/front/static/edit_report.html +++ b/front/static/edit_report.html @@ -36,7 +36,7 @@ -
+
diff --git a/front/static/home.html b/front/static/home.html index 114887d..d272129 100644 --- a/front/static/home.html +++ b/front/static/home.html @@ -35,7 +35,7 @@
-
+

Welcome to Reimbursinator

diff --git a/front/static/index.html b/front/static/index.html index 713bb3a..f759c1b 100644 --- a/front/static/index.html +++ b/front/static/index.html @@ -27,7 +27,7 @@
-
+

Reimbursinator

An open source expense management solution sponsored by the Software Freedom Conservancy

diff --git a/front/static/js/login.js b/front/static/js/login.js index 20b411d..0bdaa9b 100644 --- a/front/static/js/login.js +++ b/front/static/js/login.js @@ -2,7 +2,7 @@ function postToLoginEndpoint(event) { event.preventDefault(); const credentials = { - "username" : this.elements.username.value, + "email" : this.elements.email.value, "password" : this.elements.password.value } const url = "https://" + window.location.hostname + ":8444/api/v1/account/login/"; diff --git a/front/static/js/signupPage.js b/front/static/js/signupPage.js index 0055cce..8d348ad 100644 --- a/front/static/js/signupPage.js +++ b/front/static/js/signupPage.js @@ -1,20 +1,64 @@ -const password = document.getElementById("password"); -const confirm_password = document.getElementById("confirmPassword"); -function validatePassword(){ - if(password.value != confirm_password.value) { - confirm_password.setCustomValidity("Passwords Don't Match"); - } - else { - confirm_password.setCustomValidity(''); +const password1 = document.getElementById("password1"); +const password2 = document.getElementById("password2"); + +function validatePassword() { + if (password1.value != password2.value) { + password2.setCustomValidity("Passwords don't match"); + } else { + password2.setCustomValidity(''); } } -password.onchange = validatePassword; -confirm_password.onkeyup = validatePassword; +password1.onchange = validatePassword; +password2.onkeyup = validatePassword; -function validateEmail(email) -{ - if(email.validity.patternMismatch) +function validateEmail(email) { + if (email.validity.patternMismatch) { email.setCustomValidity('Please input correct email'); - else + } else { email.setCustomValidity(''); -} \ No newline at end of file + } +} + +function postToRegistrationEndpoint(event) { + event.preventDefault(); + + const credentials = { + "email" : this.elements.email.value, + "first_name" : this.elements.first_name.value, + "last_name" : this.elements.last_name.value, + "password1" : this.elements.password1.value, + "password2" : this.elements.password2.value + } + const url = "https://" + window.location.hostname + ":8444/api/v1/account/register/"; + const xhr = new XMLHttpRequest(); + + console.log("Attempting a connection to the following endpoint: " + url); + console.log("User credentials:\n" + JSON.stringify(credentials)); + + xhr.open("POST", url, true); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.onreadystatechange = function() { + if (this.readyState === 4) { + if (this.status === 201) { + console.log("REGISTRATION SUCCESS!"); + console.log("Server response:\n" + this.response); + token = JSON.parse(this.response).key; + localStorage.setItem("token", token); + window.location.replace("home.html"); + } else { + console.error("LOGIN FAILURE!"); + console.error("Server status: " + this.status); + console.error("Server response:\n" + this.response); + } + } + }; + + xhr.onerror = function() { + alert("Error connecting to the authentication server!"); + }; + + xhr.send(JSON.stringify(credentials)); +} + +const form = document.querySelector("form"); +form.addEventListener("submit", postToRegistrationEndpoint); diff --git a/front/static/login.html b/front/static/login.html index 9a8af2f..f8b5a07 100644 --- a/front/static/login.html +++ b/front/static/login.html @@ -14,7 +14,7 @@ -
+
@@ -24,8 +24,8 @@
- - + +
diff --git a/front/static/new_report.html b/front/static/new_report.html index 6f0506b..f1cc53b 100644 --- a/front/static/new_report.html +++ b/front/static/new_report.html @@ -35,7 +35,7 @@
-
+

Create a new report

diff --git a/front/static/signup.html b/front/static/signup.html index ebfeb1b..12b1119 100644 --- a/front/static/signup.html +++ b/front/static/signup.html @@ -14,7 +14,7 @@ -
+
@@ -23,21 +23,25 @@
-
- - -
- - + +
- - + + +
+
+ + +
+
+ +
@@ -51,5 +55,4 @@
- From fc2d2e9e9dc4867eb58d587af2ea689ca7d588c4 Mon Sep 17 00:00:00 2001 From: Preston Doman Date: Wed, 6 Feb 2019 15:44:15 -0800 Subject: [PATCH 21/32] Fix formatting mistakes --- front/static/home.html | 2 +- front/static/js/signupPage.js | 2 +- front/static/login.html | 8 ++++---- front/static/new_report.html | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/front/static/home.html b/front/static/home.html index d272129..99d984c 100644 --- a/front/static/home.html +++ b/front/static/home.html @@ -35,7 +35,7 @@
-
+

Welcome to Reimbursinator

diff --git a/front/static/js/signupPage.js b/front/static/js/signupPage.js index 8d348ad..8777450 100644 --- a/front/static/js/signupPage.js +++ b/front/static/js/signupPage.js @@ -46,7 +46,7 @@ function postToRegistrationEndpoint(event) { localStorage.setItem("token", token); window.location.replace("home.html"); } else { - console.error("LOGIN FAILURE!"); + console.error("REGISTRATION FAILURE!"); console.error("Server status: " + this.status); console.error("Server response:\n" + this.response); } diff --git a/front/static/login.html b/front/static/login.html index f8b5a07..a09051e 100644 --- a/front/static/login.html +++ b/front/static/login.html @@ -24,12 +24,12 @@
- - + +
- - + +

diff --git a/front/static/new_report.html b/front/static/new_report.html index f1cc53b..5d8dd49 100644 --- a/front/static/new_report.html +++ b/front/static/new_report.html @@ -35,7 +35,7 @@
-
+

Create a new report

From 38a9464870c0bf6aa412496007d82d990a59af1c Mon Sep 17 00:00:00 2001 From: kououken Date: Thu, 7 Feb 2019 15:32:21 -0800 Subject: [PATCH 22/32] Implemented policy parsing, applied policy to report creation, added field_name to fields. --- .../migrations/0005_field_field_name.py | 18 ++++ back/backend/models.py | 3 +- back/backend/policy.py | 68 +++++++------ back/backend/test.py | 3 + back/backend/views.py | 93 +++++------------- back/db.sqlite3 | Bin 89088 -> 97280 bytes 6 files changed, 87 insertions(+), 98 deletions(-) create mode 100644 back/backend/migrations/0005_field_field_name.py create mode 100644 back/backend/test.py diff --git a/back/backend/migrations/0005_field_field_name.py b/back/backend/migrations/0005_field_field_name.py new file mode 100644 index 0000000..caf25f5 --- /dev/null +++ b/back/backend/migrations/0005_field_field_name.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.5 on 2019-02-07 22:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend', '0004_auto_20190131_1645'), + ] + + operations = [ + migrations.AddField( + model_name='field', + name='field_name', + field=models.CharField(default='field', max_length=512), + ), + ] diff --git a/back/backend/models.py b/back/backend/models.py index bb26ed3..b59c1ec 100644 --- a/back/backend/models.py +++ b/back/backend/models.py @@ -26,12 +26,13 @@ class Section(models.Model): class Field(models.Model): section_id = models.ForeignKey(Section, on_delete=models.CASCADE) + field_name = models.CharField(max_length=512, default="field") label = models.CharField(max_length=512) number = models.IntegerField() type = models.CharField(max_length=128) completed = models.BooleanField(default=False) data_bool = models.BooleanField(default=False) - data_decimal = models.DecimalField(max_digits=9,decimal_places=2, null=True, blank=True) + data_decimal = models.DecimalField(max_digits=9, decimal_places=2, null=True, blank=True) data_date = models.DateField(default=datetime.date.today) data_file = models.FileField(upload_to='uploads/%Y/%m/%d/', max_length=512, null=True, blank=True) data_string = models.TextField(default='', blank=True) diff --git a/back/backend/policy.py b/back/backend/policy.py index 95e401b..1131e30 100644 --- a/back/backend/policy.py +++ b/back/backend/policy.py @@ -1,10 +1,36 @@ -# simple_policy.py from datetime import date -from policy import Policy, Section -# - For the rules, should one refer to fields by 'section.fields.x' -# or by the section name eg. 'general_section.fields.x'? +#### Classes for policy, sections. +class Policy(): + + def __init__(self): + self.sections = [] + + def add_section(self, section): + self.sections.append(section) + +class Section(): + + def __init__(self, title="Section", html_description="", required=False, auto_submit=False, fields={}): + self.title = title + self.html_description = html_description + self.required = required + self.auto_submit = auto_submit + self.fields = fields + self.rules = [] + + def add_rule(self, title="Rule", rule=None, rule_break_text=""): + rule = { + "title": title, + "rule": rule, + "rule_break_text": rule_break_text, + } + self.rules.append(rule) + +#### Policy configuration begin here + +pol = Policy() #### General #### Section 0 @@ -12,7 +38,7 @@ general_section = Section( title="General Info", html_description="", fields={ - "destination": {"label": "Destination City", "type": "string"} + "destination": {"label": "Destination City", "type": "string"}, } ) @@ -22,7 +48,7 @@ general_section.add_rule( rule_break_text="What did the cowboy say about Tim, his wild horse?" ) -Policy.add_section(general_section) +pol.add_section(general_section) #### Flight #### Section 1 @@ -43,7 +69,7 @@ flight_section.add_rule( rule_break_text="Fares cannot be more than $500" ) -Policy.add_section(flight_section) +pol.add_section(flight_section) #### Lodging #### Section 2 @@ -64,13 +90,13 @@ def nightly_rate_check(report, section): duration = checkout_date - checkin_date return section.fields.cost <= duration * section.fields.rate -section.add_rule( +lodging_section.add_rule( title="", rule=nightly_rate_check, rule_break_text="The average nightly rate cannot be more than the USGSA rate." ) -Policy.add_section(lodging_section) +pol.add_section(lodging_section) #### Local Transportation #### Section 3 @@ -89,7 +115,7 @@ transport_section.add_rule( rule_break_text="Local transportation costs must be less than $10 per day, on average." ) -Policy.add_section(transport_section) +pol.add_section(transport_section) #### Per Diem #### Section 4 @@ -109,24 +135,4 @@ per_diem_section.add_rule( rule_break_text="The average cost per day for per diem expenses cannot be more than the rate specified by the USGSA." ) -Policy.add_section(per_diem_section) - -''' -Section( - title="", - html_description="

", - fields={ - "": {"label": "", "type": ""} - } -) - -section.add_rule( - title="", - rule=lambda report, section: boolean_statement, - rule_break_text="" -) - -#// or, for a rule which doesn’t apply to a specific section... -#// -#// add_general_rule(...) -''' +pol.add_section(per_diem_section) diff --git a/back/backend/test.py b/back/backend/test.py new file mode 100644 index 0000000..6ecdccb --- /dev/null +++ b/back/backend/test.py @@ -0,0 +1,3 @@ +from policy import pol + +print(pol) diff --git a/back/backend/views.py b/back/backend/views.py index 70e3f79..1c368c2 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -1,7 +1,8 @@ from rest_framework.decorators import api_view from django.http import JsonResponse from .models import * - +from .policy import pol +import json # function that prints all the reports def get_reports(report_pk): @@ -47,15 +48,14 @@ def get_sections(r_id): def get_fields(s_id): # create dict of arrays for fields field_set = {"fields": []} - queryset = Field.objects.filter(section_id=s_id) - # queryset = Field.objects.all() + queryset = Field.objects.filter(section_id=s_id).order_by('number') for i in queryset: data = { - "field_name": "TODO", + "field_name": i.field_name, "label": i.label, "type": i.type, "number": i.number, - "value": "get_value", + "value": "i.to_json()", } # append the fields to array # use copy() to avoid overwriting @@ -70,73 +70,34 @@ def report(request): ''' Generate a new empty report and return it ''' - data = { - "title": "2018 Portland trip", - "date_created": "2018-05-22T14:56:28.000Z", - "submitted": False, - "date_submitted": "0000-00-00T00:00:00.000Z", - "sections": [ - { - "id": 1, - "completed": True, - "title": "Flight Info", - "html_description": "

Enter flight details here.

", - "fields": { - "international": { - "label": "International flight", - "type": "boolean", - "value": True - }, - "travel_date": { - "label": "Travel start date", - "type": "date", - "value": "2016-05-22T14:56:28.000Z" - }, - "fare": { - "label": "Fare", - "type": "decimal", - "value": "1024.99" - }, - "lowest_fare_screenshot": { - "label": "Lowest fare screenshot", - "type": "file", - "value": "e92h842jiu49f8..." - }, - "plane_ticket_invoice": { - "label": "Plane ticket invoice PDF", - "type": "file", - "value": "" - } - }, - "rule_violations": [ - { - "error_text": "Plane ticket invoice must be submitted." - } - ] - }, - { - "id": 2, - "completed": False, - "title": "Hotel info", - "html_description": "

If you used a hotel, please enter the details.

", - "fields": { - "total": { - "label": "Total cost", - "type": "decimal" - } - }, - "rule_violations": [ - ] - } - ] - } + + # Create the report + report = Report.objects.create(user_id=request.user, title=request.data['title'], date_created=datetime.date.today()) + report.save() + + # Create the sections + for i in range(len(pol.sections)): + section = pol.sections[i] + s = Section.objects.create(report_id=report, auto_submit=section.auto_submit, required=section.required, completed=False, title=section.title, html_description=section.html_description, number=i) + s.save() + + # Create the fields + j = 0 + for key in section.fields: + field = section.fields[key] + f = Field.objects.create(section_id=s, field_name=key, label=field['label'], number=j, type=field['type'], completed=False) + f.save() + j = j+1 + + # Return the newly created report + data = get_reports(report.id) return JsonResponse(data) # List of reports @api_view(['GET']) def reports(request): report_set = {"reports": []} - queryset = Report.objects.all() + queryset = Report.objects.all().order_by('date_created') for i in queryset: data = { "report_pk": i.id, diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 8074d09696b7ab103c40188a656433376bef08ba..77fd67fd08e54caf24731ac1e3dfd3ef6ad93a2e 100644 GIT binary patch delta 12088 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 TOVPAFnN74?9o9``L`DA(muqBP delta 2260 zcma)8du&rx7(eHHx9h!Y?*@}OHc-0_onsE}qwO|?g-7W&la8n`Y<*zY-fex)wuF~v zEFh@CL_KQ#Lk&Sp^be!)h75@WgT|;azRiq}Kh)?V@r4O!#2CMO_vj)TZEk<3=k)hI z&hPt9Pxt=j*n8aZKtm1rlMu3X=1p64R8U@!&&$qrr<01 z0zQEc;T?DrPQhz%0*-N2ESQu&&-e>V99LWX5rmKh8zKnT-Hy<`1z}}BLhBlYt2FZq z@C(&ffEOMD2RzH3Vc)QCOw}D_d|%~y+RI_p~p8u?^Y10(7t6kCB6`w~@S9!beS<%(0cjy|@50mlMbz+??w~5kt6@N?nb)ny* zsjKkudRHi_?(=t=ALv?OQ4{zGe2p4U!uxO+`~=@Y%Iw~GH{)x?$4uXzcLivIt=zeH zqq%UY3;5Q3&$$_##~5V5s*<_jjc>s`f3Qk`YLes5LmsY)y=LyvBe2vBCkgxkzrru@ z1AGP_!@F3+Dfkjzg_G#*3FvhIrGnc=mxZj-M#)CeMyG{PVWUF;i3%2g1q?uvWOf^I zn2v{UVYJp9eDnwv8Jr_<4lZDb?_i1Tgb6?;kTGciDkz+Uov<1zkZ_)j>4HQ=QEcp^ zv^Q5Y(w@HTP;T{T_w*!z6HnYI#PW$ztN1HcuN>`WjI097N@@&K>EEno+T~*F4Ge81 zu{j~pV0tVuJW`yE87K$xsY>?u}_1KD>cuQ{ypPmai?%LeJ0Qd5k+Tw*c0n6{eLN6t~V0B0zc^ei6FGbrDu z&}8c?psrYyX|3(5pl1dL2_D#k$lC*B*D@z*(M77?Xkg#RJvZ3rX1a^jc1`yv$|}u^ zUCd_Jbk$m$eyEdNsY_H3Ch~>i-)vR?jIHW}SzEPZW=-p`HtD7f_Yim+4nqN|*(5v4 za%??YN~h=vdXK4!BXmr0%cPwy5k(@)B5my7o*6XqRuQt6{sor6vpQ_#h1m$Y+UAl; zi&Q^n5zQDDf5d8{LNTAn4$mX&l``p~wX@`4G;eqcMl>HA@nCNm##pw1hQd%HZOjv3 znIx0ia#EHR#En=Y6HU)!wTUumE&C1_qtSeEI|hhHiw3iyoVD(hiBFo_XCH1WpN$sB zu(zY>nQj}*<Md=2zhs_m0SN#rK9?PWJ67*tudUNSSJh}^;KMUS+ zhJ%7F6&hw_JYg3}RaS~m?N@?j!!|tOsFox;v4qoxvudr)zkzK)NSVBx*`nDyLUQTH z2(1sQ?W(3xTOdiY8bNBD73d%IDLb?7E(#Z{2!6Q0RiV=izIP1jaqbf;5i6jXz~|5m zy)c3IPX^CKHC(w2LNw+biSEiJ{h4e^%jr8hRCVW$RAzgpH1+-xrhtzY25$O;(`B4ZBrnnZwdqx;mmc( zNML;`lnjpaC;O9OZ6MX(gP*pBlt?DDYt!aFCA>MLgm!OH`!{pX8C6u{di}Y+% zBgwED%JeCbz`EW2T6kx8_pmRL?AsCEjNc?9$xt%v4JX4oj{J_v26`huG&xwKU6i}I z|Kt0z4F14B2fd}60(7|QCQnmge09oMXKbM3x0V`PXg&Y4(mC-%fYw#J1$LUi0f?|4 s*=dyIMK*DIfOgYGRt;xf12|fLAbQZ}E2SqydaSfqqn}O0gY Date: Thu, 7 Feb 2019 17:13:43 -0800 Subject: [PATCH 23/32] added filter by user_id -- now reports only display based on user id --- back/backend/policy.py | 6 ++++-- back/backend/views.py | 5 +++-- back/db.sqlite3 | Bin 97280 -> 97280 bytes 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/back/backend/policy.py b/back/backend/policy.py index 1131e30..d40f56e 100644 --- a/back/backend/policy.py +++ b/back/backend/policy.py @@ -12,7 +12,8 @@ class Policy(): class Section(): - def __init__(self, title="Section", html_description="", required=False, auto_submit=False, fields={}): + def __init__(self, title="Section", html_description="", required=False, + auto_submit=False, fields={}): self.title = title self.html_description = html_description self.required = required @@ -75,7 +76,8 @@ pol.add_section(flight_section) #### Section 2 lodging_section = Section( title="Hotel Info", - html_description="

Enter hotel info here.\nPer diem rates can be found at

", + html_description="

Enter hotel info here.\nPer diem rates can be found at " + "

", fields={ "check-in_date": {"label": "Check-in date", "type": "date"}, "check-out_date": {"label": "Check-out date", "type": "date"}, diff --git a/back/backend/views.py b/back/backend/views.py index 1c368c2..b04e358 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -2,7 +2,7 @@ from rest_framework.decorators import api_view from django.http import JsonResponse from .models import * from .policy import pol -import json + # function that prints all the reports def get_reports(report_pk): @@ -97,9 +97,10 @@ def report(request): @api_view(['GET']) def reports(request): report_set = {"reports": []} - queryset = Report.objects.all().order_by('date_created') + queryset = Report.objects.all().filter(user_id=request.user.id).order_by('date_created') for i in queryset: data = { + "user_id": request.user.id, "report_pk": i.id, "title": i.title, "date_created": i.date_created, diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 77fd67fd08e54caf24731ac1e3dfd3ef6ad93a2e..fe3ce3eff3b1cdb31aac803e57d19c86f8d8abe2 100644 GIT binary patch delta 3272 zcmeH}du&@*9mmf(KWA~`=H@Y9vvetQnzW6b*uK8kkJziGMz~3n)=rbS4?9oSzG-sp z*s1HRr7*Rr22`lpV0Y53P*v@ZQdL@kc7|@6(1sX7P(d~E2c>9&iNE-3Fb!1|MT~Qf z^668s&l?7=EH?3|50j)X)%%Zqu zhi;eK^*_s@&9dYTxg^;o_1h(HSn3b^gKkL)DM3YdC|><*-lMIwMhg3suq?Udep&HL z`g!>|6IJxGep~*8Rnv|^Rvnam{ek}SuM~MI=>!vkzrtVOBlsiy0X~3V!6U#-5=jQYNnwQzO7fYn!dNT=-mh+l603H`rJkB63>mm<7QDN;Cxz0Fj>& z3E$Rj7hlJcu}QgALeMGvQ&)5Y1x*~@5kaymGBny3tb2!bEOix4Rb zR|C-goUITL$Lkm0%&g5K`n*p#}B$(n9e0Qm$0gjs>&FPpa8a zREy;jrv|m8mRn3}19CJTmFf3X^wjubEPjxdrRAs=^(NwjxfpE~lgFfJM7Q7R@MjiA z{6+oz z9lP%PUZi6rR1F8RToVrbvR4U~Pk!h86PwKBE`l!V&3nk*vhe+%lWpA)#s6+ujpe`J ze4@^3h6Y4K!DV<4z5?^qt%snY+}iOm(RXuopyfms}!g zvIGAHe;1#`J26H-Md#5Z-C~7!4jS(y@KZ+L5^k$^r3=SP{RfOoCG2c*r5Dt6*0q?Q z&7?|dC~jOUVyC!PT39JniYEjVG#ek3uvG6V(sto-mr<8f#nMVq z<=uQ^Mr;MQ8-p{rS?DXOw4yRi&wk@edE8~`n@<(h=%|3AX2X-m&dwu+LQYNPYernm zm(*fDRaz|MQ@L==_%M&%LT^SrURtb_hN2b8&dNeQle}+TvXe{R`&h}2ha`{GNOsgp z9P zhn1&DrYH_g+?>NElOmwA2%p0-yanEduS10ViCiWc3E@xhd*}|W^wP%FPe>JzqrrH2 z7H{uWHkzH15m1*|G@DUp6HOak#o9^^O0~KHRec>TECuN_d+^V&Ne&^UzGvXEROLgc2tYB~z79vgUznp=5Z{xHN?$ z77uGOkz8Mihp!~Dar|aab$s{Xbt!Hx<Ca^H;7CwpGzrdo!>F z6n-;!+Gdj9Gf?K^LUq2*%05W&JAy)Y5IS|LpS-EH=ixx(?BAX(M)W#Hy@n9b*6s+)ZAbQ delta 2760 zcmcJRZERat8OP6ak7GM&;^to0j$h+z$FE7_*w>EVmUg9YX(ufkG!;wRwQ-Z1G^%44 z=Y|v{wgv&3rh&TMsiz;h7odzn1{!#zXhN(K2#IMR7$2ynsX`MU5E2NOm@0Luc+Rz* zCF>ZU$hqgId+vG8+w(uq<6OAiap88yMUM^c5JFC2J&D!)bUY`(ogYoV-Q|c$+i3z$ zmuJqZ)!9>Z^<1s4+4YCE9fgC9?`%5}?m>Gh*a@8y?7|xjTj~V(YKuxLT^vp+!>OFC zq)Ygua>;zESQyRecI8ZDR8}&jY@w9NC$oioE}NdKm#b&@7);L877y|!w-ocTqLh?k zDVtAbas@@n>rW}WO{?A1rvFxXui2f=mqv5RbS|Z2ijB82%86sdM2K+v|4|y}E<7RV zdrXpk`?@$4VO_9Neq?nC|~x)=G^$fuBhj_g6+irkO98QG0|E4&N&W_S$wtMGlu z8{rc2wSgk?)ldQX!%!Z1EtErkD>#b063ikm$r z%|&-!S%aYdyXQ)DH4$TLRk+rH!-PjJEyAPx4c^y%FX+bGN&U^|Gk*RpYPDJ;JysZ3 zt7^Smkq=krYW%y6y>UeD!N|*3O+WY3ELvuydyz zvU8{GwR5M8N!%$pi901F$;d&8J0&b}r}T^5DK3#aMH0QpZqb7@i|+QZ={{Z>wre@s zW4Dk@#tNASYfGA}e|>F~yXA{|?^;IR{yj5q>}ofjdD&zY;5-r5;d~=)tw7`a51ul2 zS%kZU4$yb#p+@hkzvg!_*0{TF?vN}rPUySzD*XlhDxIToI^Ga{64g6j?`e#_{`<>v zH=)0zPtYUOBiusmW`sEW4Soh+hR;AZxlR`Kv~}EkC}AT;9bTxOn#GYLVHQxq)zo^`*jTxeklDXK2Vsk6u3T430k(Szd{YA7 z%%%~u>bY`VTdu3d^!a`pNq4%fRub&NtLHu(Ta?T4l2%`+&dYNPYGtJ8jP6U5sFKUp(4tS2e ztwA1VfYU8m*)F^xyeq~YUIqob$Uj@MvOg_>B!#yqiQV614;_bKXP9e=&6P`^hdfR| z#@Ns?*x5a>$xrLkU@|$a5F+$1^cCt7)`c$k7rcfaZs5&-Ntouj=#)uXb;zu|2+vX} z7tr5$ew0eiewM0&1G^G_BTrFr+GiMxs}66|Sj>40W6|k0jQhkMp+YR=1`)dGWP2gu z8ZPyHVLEDzwy!!O&C&K;*cfeh4j7}Uy}27BpN(M}ENtXRlYKQ2GIsHR#I@f}#tB`c zWh1J;Eqp;pz_-Z%wCy-0ZV`jUfjv+AtOkn{!QW^7_^ZCz;AFgcyF%pw@>e^t^v@W5PbOmPFpHykR&%z@^$m1$41Tq8(D$k$7DN~;d!^=`QE&1V?QoT z#@0_t#x5?y{=SxEeeHosXH&91LnX(D`FDqNi&Ui@n2dnEqe0+fcI7k#w6iBsV@GRX zTfC%%H>tI?tMedQoP4R0$n)ut!?9HoOgpWg_>=9-5^QA_<7RdsAI17vtS7J@!+IPO cR^a-58az&I`Aw;%72B3pY+t{#0v)FR0G_7Exc~qF From f19781a68209f5ac0ef1c569c7febb2067c8cb57 Mon Sep 17 00:00:00 2001 From: Rupika Date: Thu, 7 Feb 2019 18:13:32 -0800 Subject: [PATCH 24/32] added function that displays data values --- back/backend/policy.py | 1 + back/backend/views.py | 28 +++++++++++++++++++++++++++- back/db.sqlite3 | Bin 97280 -> 99328 bytes 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/back/backend/policy.py b/back/backend/policy.py index d40f56e..e325284 100644 --- a/back/backend/policy.py +++ b/back/backend/policy.py @@ -61,6 +61,7 @@ flight_section = Section( "departure_date": {"label": "Departure date", "type": "date"}, "return_date": {"label": "Return date", "type": "date"}, "fare": {"label": "Fare", "type": "decimal"}, + "layovers": {"label": "Transit wait", "type": "integer"}, } ) diff --git a/back/backend/views.py b/back/backend/views.py index b04e358..3ef2682 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -49,13 +49,16 @@ def get_fields(s_id): # create dict of arrays for fields field_set = {"fields": []} queryset = Field.objects.filter(section_id=s_id).order_by('number') + for i in queryset: + # function to print corresponding datatype + key, value = get_datatype(i) data = { "field_name": i.field_name, "label": i.label, "type": i.type, "number": i.number, - "value": "i.to_json()", + key: value } # append the fields to array # use copy() to avoid overwriting @@ -63,6 +66,29 @@ def get_fields(s_id): return field_set +# function to convert value into JSON +def to_json(convert): + return {"value": convert} + +# function that gets corresponding +# data type +def get_datatype(self): + if self.type == "boolean": + if self.data_bool: + return "data_bool", True + else: + return "data_bool", False + elif self.type == "decimal": + return "decimal", self.data_decimal + elif self.type == "date": + return "date", "{}".format(self.data_date) + elif self.type == "file": + return "file", "{}".format(self.data_file) + elif self.type == "string": + return "string", "{}".format(self.data_string) + elif self.type == "integer": + return "integer", self.data_integer + # API Endpoints @api_view(['POST']) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index fe3ce3eff3b1cdb31aac803e57d19c86f8d8abe2..9b7a3db3c49816018aeeb88b745028bf5b925f37 100644 GIT binary patch delta 1215 zcmZvcUq~EB9LMK3ztuZE?>w!StC(mKXo-sE&KU3Z4q5_-#grO@wrMm~*Skq_sC(z$ zo_}JZ27CyGQp1)^p{Y${8YQ-1dZb684`=y zKg-N-XMW$`%y)KXqhRJ-;art_kr1MZN4E2OLa=zff3?^bEic7d7|`N_Oi%O~ES)k; zzjesm+k=~&{&|CC7`VC#7*K$E;fOZ!k zKy+GiO7e`&$Z5$*o9Zda3CVHEF`MC0$*iO)nUOSXhDH_?tDr=|hXkMEpZEwL=DZ)@ zM>~do>(M9MN+_<|h4tezT+ewgKEPtpJGNh-XYbdS6a_2roaMN()2g2<&IPX=!D@T5 zKPnlKR3*cbA?xa5uSn=6cnfDShTaA561toG4&vMAgndU2v~^k6mtL~c%N4oU^34^m zf@`(_%@%-8ur0s_C{6 z59r_nf4*Z#1Qn6s%L~I0!LvS0pIhgiFaA1Qy_3{2o8VE>!4! zI!|@l3>#2RekUJ@aLbm=&G#O|LwwFEr<3e*yPe=`jiva^7(_}!Es3n5naPyisq^|V zXy-f)ll1?}as|bQEHdaJA>hB5P{Ttb@CRSXKnD*d;4n`a(DUl1K1PI|ChEl7a1Sm( zE4avA@)=>`aJtY#zde7z$D=0H(eNqW!Jvwt$U>=Cjh|%k!G@&Xmk^ouPVgEAFIUn8 zizkP*p{77kZ3r|q1VU;&l`++E{yu}cvgeahSyRqZ$M~ggXm+W#*!EEmc?nQ&4!nW4+-wV_CszjhSr%fbnk)(kUiFu7i{$=kC~$pbx5S{^o-2yDvR z+){qH2WlMQ^w=?h2H))YI#@1!B>if(Ou<7qyh zhFV9&t|~SuqpwG{qRkl(d8O#Z$?fPeG(D3vcaCXEk;G&tnDL*AhO~*)C^Irw$3c-+ zDHLWC|AAF{nHJ+b^opB*5b$hmRN6`LKlj*2=x+&Ix99hx|Aig7u;W({vF?7_=knXf e3V4Iyja=FG&#|O)%0mXFthQ-+0}7(H{C@y53_=?K delta 940 zcmZuuO-NKx6u#%3`5))UY1F{-e;OUqW=xz$sg#~dNTXzinmRt6XZ|tscs`|#FqI28 zmG%}_NXpPmsD(9)iB=M>DhgUfi`vyrkU~UTbf2ghbT8-Q-t+sNa}raA#FlphYnm)jf;6^8TW3|zu1O3&J5-eAEhG(?`@8=OR*yT9OEM)lG1X{b%|&sJBQ9Bwi{(#6Vd;s*CH@+b79m44bn}CPHK5&}iV}c2Z}itJfjusEm%uf-)G7h5PN~640;h;G-3zkaujq zeSA&2*!v%0d~#{E0zOmlgjV5HEq$!8@dQP189kcjObu-o!RPk$4TycirGv3ZR8Yjw zdB)zXvG*H2tgaY3N9SemHSW2^$CO>ainDf72pNoVzRhNW!povECdcx$6sSSDKM*SQ zmzVm3Me?p`HwxE4IMjm6Su_|^L^-zGpDK*9t_S_us=99n`}BGL6(89J1|?l`{ov&-jg6~^=j?% S7xq0W4{yPIu!W@?p!);)f&EDU From f8b6d665c7a0f609da7a074713529d8bc49dd263 Mon Sep 17 00:00:00 2001 From: Rupika Date: Thu, 7 Feb 2019 18:21:57 -0800 Subject: [PATCH 25/32] changed the data_values to display as just "value" in the JSON data dict --- back/backend/views.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/back/backend/views.py b/back/backend/views.py index 3ef2682..ff7facf 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -52,13 +52,13 @@ def get_fields(s_id): for i in queryset: # function to print corresponding datatype - key, value = get_datatype(i) + value = get_datatype(i) data = { "field_name": i.field_name, "label": i.label, "type": i.type, "number": i.number, - key: value + "value": value } # append the fields to array # use copy() to avoid overwriting @@ -75,19 +75,19 @@ def to_json(convert): def get_datatype(self): if self.type == "boolean": if self.data_bool: - return "data_bool", True + return True else: - return "data_bool", False + return False elif self.type == "decimal": - return "decimal", self.data_decimal + return self.data_decimal elif self.type == "date": - return "date", "{}".format(self.data_date) + return "{}".format(self.data_date) elif self.type == "file": - return "file", "{}".format(self.data_file) + return "{}".format(self.data_file) elif self.type == "string": - return "string", "{}".format(self.data_string) + return "{}".format(self.data_string) elif self.type == "integer": - return "integer", self.data_integer + return self.data_integer # API Endpoints From af2d74853606583faa91f7461523b387a6837a3b Mon Sep 17 00:00:00 2001 From: Jack Date: Fri, 8 Feb 2019 17:26:45 -0800 Subject: [PATCH 26/32] Display completed report. Login and go to report history and click on "view" button and the report will display --- front/static/edit_report.html | 14 +++++++++++ front/static/js/viewHistory.js | 46 +++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/front/static/edit_report.html b/front/static/edit_report.html index 80d39df..5875c76 100644 --- a/front/static/edit_report.html +++ b/front/static/edit_report.html @@ -81,6 +81,20 @@
+ diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index 802da82..ccd2a89 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -254,6 +254,8 @@ function displayListOfReports(parsedData) { dateSubmitted = new Date(reports[i].date_submitted).toLocaleDateString("en-US"); actionButton.classList.add("btn-success", "view-report-button"); actionButton.innerHTML = "View"; + actionButton.setAttribute("data-toggle", "modal"); + actionButton.setAttribute("data-target", "#viewReportModal"); } let dateSubmittedCell = bodyRow.insertCell(3); @@ -267,8 +269,50 @@ function displayListOfReports(parsedData) { } function displayReport(parsedData){ - window.alert(parsedData.date_created); //Able to get the correct report ID now just needs to display the + //Able to get the correct report ID now just needs to display the //report as an modual + const modalBody = document.querySelector(".modal-view"); + const modalLabel = document.querySelector("#viewReportModalLabel"); + + while (modalBody.firstChild) { + modalBody.removeChild(modalBody.firstChild); + } + + // Add report title and date + const reportTitle = parsedData.title; + const dateCreated = new Date(parsedData.date_created).toLocaleDateString("en-US"); + modalLabel.innerHTML = reportTitle + " " + dateCreated; + + const card = document.createElement("div"); + card.classList.add("card"); + const cardHeader = document.createElement("div"); + cardHeader.classList.add("card-header"); + const cardBody = document.createElement("div"); + cardBody.classList.add("card-body"); + + + const sections = parsedData.sections; + for (let key in sections) { + let section = sections[key]; + const h4 = document.createElement("h4"); + const value = document.createTextNode(section.title); + + h4.appendChild(value); + cardBody.appendChild(h4); + let fields = section.fields; + for (let key in fields) { + let field = fields[key]; + const p1 = document.createElement("p"); + const p1Value = document.createTextNode(field.label + ": " +field.value); + p1.appendChild(p1Value); + cardBody.appendChild(p1); + } + cardHeader.appendChild(cardBody); + card.appendChild(cardHeader); + + } + + modalBody.appendChild(card); } document.addEventListener("DOMContentLoaded", function(event) { From bfef35a37855afe6d6bce2d526a17500be0a9a33 Mon Sep 17 00:00:00 2001 From: sliang17 Date: Sat, 9 Feb 2019 12:27:09 -0800 Subject: [PATCH 27/32] Create the title textarea in new report page --- front/static/new_report.html | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/front/static/new_report.html b/front/static/new_report.html index 5d8dd49..30a91f7 100644 --- a/front/static/new_report.html +++ b/front/static/new_report.html @@ -36,8 +36,21 @@
-

Create a new report

-
- +
+
+
+
+

Create a new report

+
+ + +
+ +
+
+
+
+
+ From 8416c041d0989765d3779ca340e881b4684fbb1c Mon Sep 17 00:00:00 2001 From: Jack Date: Sat, 9 Feb 2019 12:32:28 -0800 Subject: [PATCH 28/32] Add a condition to check if section is completed. If its complete it will display the information of that section if not it won't display --- front/static/js/viewHistory.js | 38 +++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index ccd2a89..f91b68d 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -285,31 +285,41 @@ function displayReport(parsedData){ const card = document.createElement("div"); card.classList.add("card"); + const cardHeader = document.createElement("div"); cardHeader.classList.add("card-header"); + const cardBody = document.createElement("div"); cardBody.classList.add("card-body"); + /* + const displayTable = document.createElement("table"); + displayTable.classList.add("table table-striped table-responsive-sm"); + displayTable.style.visibility = "visible"; + cardBody.appendChild(displayTable); +*/ + const sections = parsedData.sections; for (let key in sections) { let section = sections[key]; - const h4 = document.createElement("h4"); - const value = document.createTextNode(section.title); + if(section.completed) { + const h4 = document.createElement("h4"); + const value = document.createTextNode(section.title); - h4.appendChild(value); - cardBody.appendChild(h4); - let fields = section.fields; - for (let key in fields) { - let field = fields[key]; - const p1 = document.createElement("p"); - const p1Value = document.createTextNode(field.label + ": " +field.value); - p1.appendChild(p1Value); - cardBody.appendChild(p1); + h4.appendChild(value); + cardBody.appendChild(h4); + let fields = section.fields; + for (let key in fields) { + let field = fields[key]; + const p1 = document.createElement("p"); + const p1Value = document.createTextNode(field.label + ": " + field.value); + p1.appendChild(p1Value); + cardBody.appendChild(p1); + } + cardHeader.appendChild(cardBody); + card.appendChild(cardHeader); } - cardHeader.appendChild(cardBody); - card.appendChild(cardHeader); - } modalBody.appendChild(card); From f3d76adf3c959a35537d01114562106ea3a35eb8 Mon Sep 17 00:00:00 2001 From: Rupika Date: Sat, 9 Feb 2019 13:23:01 -0800 Subject: [PATCH 29/32] extracts just the file name from the file path --- back/backend/views.py | 40 ++++++++++++------ back/db.sqlite3 | Bin 99328 -> 99328 bytes .../2019/01/31/CUqADRaW4AAb1QI.jpg_large.jpg | Bin 69891 -> 0 bytes .../02/09/Supreme-logo-newyork-1920x1080.jpg | Bin 0 -> 76734 bytes 4 files changed, 26 insertions(+), 14 deletions(-) delete mode 100644 back/uploads/2019/01/31/CUqADRaW4AAb1QI.jpg_large.jpg create mode 100644 back/uploads/2019/02/09/Supreme-logo-newyork-1920x1080.jpg diff --git a/back/backend/views.py b/back/backend/views.py index ff7facf..1ddfa00 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -2,11 +2,11 @@ from rest_framework.decorators import api_view from django.http import JsonResponse from .models import * from .policy import pol +import ntpath # function that prints all the reports def get_reports(report_pk): - # queryset = Report.objects.all() queryset = Report.objects.filter(id=report_pk) for i in queryset: data = { @@ -28,7 +28,6 @@ def get_sections(r_id): # create a dict of arrays for section section_set = {"sections": []} queryset = Section.objects.filter(report_id=r_id) - # queryset = Section.objects.all() for i in queryset: data = { "id": i.id, @@ -66,10 +65,6 @@ def get_fields(s_id): return field_set -# function to convert value into JSON -def to_json(convert): - return {"value": convert} - # function that gets corresponding # data type def get_datatype(self): @@ -83,12 +78,19 @@ def get_datatype(self): elif self.type == "date": return "{}".format(self.data_date) elif self.type == "file": - return "{}".format(self.data_file) + file_name = path_leaf(str(self.data_file)) + return "{}".format(file_name) elif self.type == "string": return "{}".format(self.data_string) elif self.type == "integer": return self.data_integer +# function that accommodates if +# path has slash at end +def path_leaf(path): + head, tail = ntpath.split(path) + return tail or ntpath.basename(head) + # API Endpoints @api_view(['POST']) @@ -98,20 +100,25 @@ def report(request): ''' # Create the report - report = Report.objects.create(user_id=request.user, title=request.data['title'], date_created=datetime.date.today()) + report = Report.objects.create(user_id=request.user, title=request.data['title'], + date_created=datetime.date.today()) report.save() # Create the sections for i in range(len(pol.sections)): section = pol.sections[i] - s = Section.objects.create(report_id=report, auto_submit=section.auto_submit, required=section.required, completed=False, title=section.title, html_description=section.html_description, number=i) + s = Section.objects.create(report_id=report, auto_submit=section.auto_submit, + required=section.required, completed=False, + title=section.title, html_description=section.html_description, + number=i) s.save() # Create the fields j = 0 for key in section.fields: field = section.fields[key] - f = Field.objects.create(section_id=s, field_name=key, label=field['label'], number=j, type=field['type'], completed=False) + f = Field.objects.create(section_id=s, field_name=key, label=field['label'], + number=j, type=field['type'], completed=False) f.save() j = j+1 @@ -119,7 +126,7 @@ def report(request): data = get_reports(report.id) return JsonResponse(data) -# List of reports +# View the list of reports @api_view(['GET']) def reports(request): report_set = {"reports": []} @@ -139,21 +146,26 @@ def reports(request): return JsonResponse(report_set) +# actions for an individual report @api_view(['GET', 'PUT', 'DELETE']) def report_detail(request, report_pk): + # view the report if request.method == 'GET': data = get_reports(report_pk) return JsonResponse(data) + + # submit the report elif request.method == 'PUT': return JsonResponse({"message": "Report submitted."}) + + # Delete the report elif request.method == 'DELETE': return JsonResponse({"message": "Deleted report {0}.".format(report_pk)}) + +# update a section with new data @api_view(['PUT']) def section(request, report_pk, section_pk): - ''' - Update a section with new data. - ''' data = { "message": "Updated report {0}, section {1}.".format(report_pk, section_pk), "fields": { diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 9b7a3db3c49816018aeeb88b745028bf5b925f37..239cbcc0f5b50c0b04d37c5a2d5929910d88c87d 100644 GIT binary patch delta 687 zcmbV~KTH!*0LI^+Ui(VHfJG5uD5!uTZQs4S-aitP3N?}l#xN*Rg0**)(xX=?m0Ch5 z=s=>0$R)Dd&1eXD3OW!5CkGdGG11w{iNzRAtT^ak9Gt%|Uw--JtE_k{E8f*MxN*O| zA8u@3-Sxq@)eymO&Fu*EL&dcMVGn)*g6@MrSMO1nEY41j=dGFPOrel*axysFh{c0P za5uV^Ol7T{IX;oGY!g)Yr$F2Bx*))C3gA)nkk?Zm@&Ewtxh?FD8)TDBdWeYzWrn0h zWJP7N?%rjm+)-&ip+-zKL@h!!O_n77Mq&e4K|8LmbOE6qeyNl~UI9Z$6#lXt7i!s_ z>#JlD+T%^_i%9TbKUDaa<@yFsN`FFwG(z(W3u9z^sSIxk1mR(TpW)$};L|u`E`bB! y1Uy6t=$LCDuqA#mF>-z=5jrz?E@4h&Z0k4Je^K=8KWT7rJ%0lZ2z@E1F#7`wFu|+< delta 583 zcmaKoPiWI%0L8yQ{gc^ltjg5d3K7LRq#^mznx>w{YSlqfTZ59K)Y*2VNxE)pH){{t zD#$>=t{=Fwco+;tByQ8w4m&A$@lpgmdGO?Y2!g?@An)+t$K%0!-Bn+A)z^=}jkV}B z+<0?q*AE9TSO&xQ^h979CTTSg_k@n(7=0EveU^i>%Ppg{P+h9mn$22cJ^>DoV*%ct zEnC(3N@=cEwJW7k!>$CKAA!iJ10Ml~Ccrv6x+BpIAUd(_{~JH>VxtzBW9z0Q=^ zh5OXswVY7&5pwn)1V?=`+64HQ6YQ_MsS#&$a3joc0ByrI;HcnXDfcp1Xp{|EBpunP zHtUA8(z07i=AvXZ+f_?eOx4yqS+i)`wW2vi6ip$nI!dQdQ?+X@D-*?31YOJ8s+&?t zo>wxI9Y&KCBd29ewXPbvX_)GDg)eHBsG9|=Sf4R5>)0N=!u=qK7iJ@-iq?eseEq1OlT7QkCBd5(iu?~MU# UB*HM@^8NLN6`1j!FE^U4KMdxw*8l(j diff --git a/back/uploads/2019/01/31/CUqADRaW4AAb1QI.jpg_large.jpg b/back/uploads/2019/01/31/CUqADRaW4AAb1QI.jpg_large.jpg deleted file mode 100644 index 151c5b510877ede9a6ba2ccc98a7d1dacf0b4411..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69891 zcmb5Uby%ED&p5ic%i^v}ad$25?(V)g#ih8rdvTZIuEniT+@0d?lyZ2U_x*lyuJg~C z-D_qtnI!jSGP!eY^1l4O4M3Nbl#v8LKmY&`A0NQ`8bAyH0|gBY4F&Vj!N9=4!Xd-M zeKa&ABm`t28U_Xs4G6@1x_NilILKole(A`()Pf0#ggkix;j zp~AzXl3)R`NdAAf_W=M99zqY21`2`#011SE0z$kG0ti2z6Xu_%{a+0V0umYq76A8w z#Q#7*{a;7`Bos6R%=;<;843abi4KMSLB7&Vz*6lw`v}kd-GfquGy^z57G_SfV!k?j z^D3&2-s~otW>rG&JU_^2VYR8(6DyZKo6FzjxcDtPK_jNsjV>KQF|?pU z*PtaOG$c!r5k>kpBZB6L{gnK`X@$N%BmH`ZJ-b1#_Dxx4*F(|9y4Gz9e9rbKM<}4@ z4z?sH5IJE1PNZyV?r8PyMu`zzSwXal$!d4rVrG<4=O0|XIEl`;;6qT`3RFLJNrh@t zt!asKsYr`D7ptkATxqNF3+||) z3SKYqtHWN<)y>mG6U*y%8-M&s_SB_;Y79Y(2Nx9(${17_p&^D0UU&1~+{g8@}8FTKHC#MB_pQK`Kq zB;+fR93Z57gcX@U+61XqQ5kZE`|~_oxjcA6!%pHhUae2<_}3XbTkS0e2TPvT1c(JD z)*4so+r5brfzFf-1bLg2e(-E9Z0K#9QST-DoshQ2zU2e=se#P$(8}|-GOdab&5hq2 zwIb!$QQ~BDowgY(ND|*>Z)WMLZ@F{(2qXX)88PCQSQQ!?%HZ?rk02D00$z zzAxn-IaY*Nus^04tSj!$_IS9xLe!?n+7`so@qz`Brn|A$dkXhGoJNX>fbqbIDNM{( zbBBTRqQk0RuxA#Xf#19=HoY86GJTBry6wgU(SudgZSby}-R}|`KBaRP$5xKCOipa{ z5lH6LT4S*hPpO2sMvQC5x?B+&RpbHNYN9ed5M6v|-o~@X`N~vxHXCUK+D~?5b9)*|iC*yz-Td8dBj;F_Y=L zVeF`K_c8yH%4mb(HFTgSkiaHkLsvTuge2}F@M9H{2X_sOMHT%LgHKxsp@!89^v2Db z6aDSW6k?YocPrg8lXC}dv7|hZ`yHK{!8nhcC1+Zxc9TUO@bgYY znpG2#re+~w+I{;dedG%9N~POVkscX`ykaEe!7eP3e9#S}`s{K?Buuxf6wgh;MyZ4F zEdlJn6$gwq_e)yMVf?WHP!*9($NYH=Y}RR<3t3kVU*2k2a^2h^$4v8|XiNW#ZFAGy zX%oG}ywyT+BsJjEk-=CcN8YzN z>mWs0B#Fp#xSjREw>Inn)z3fN19Sbqv6jTv8OpKOc|f?tkT}wt+cYjM&Gc6NzN>J9 z4eYwi-8>$d;>~fmMZll$?;-YHK2RVL(|+2B8a9hWpCI@qA7p)T3u=aB7=@vZTnE{R zV)zkfTCp`1KVgui9;9N?ST$8;+M4mQD-jjx%nvo&hdPbk3Ig(b)}1JBh~lg(=Mj{^ zY7=BOw*=a{7m_O(UDG_DfCp;l^XG=2EhYQyd@n!OG-M&4@C(2?$QOR8a`R?5E#cOR z`rR%pmBWT<36Q>lP%0f3O!tc0{T}mJu4Crpfd`F8055KXQ;pF+%BJrH#~==p0lSd6!$j5V8f8xGn~sAS67h;BQcg)%5)#3U3XwS3eaYu8K^DA_kM`3r=kJig z2Z?d7#uG2(#iV!y@s`uwKzPu+WZRan7?eyLQ`%%IuuabKu6rsYLtbIuY`y5y(w#7(>SWYKI^=?i`Od7L(%i%RcWsIA zf&CzOiM|t1auV4DRjEzo6v5rCt0P4w=9YyVNjMGG6Z6N#5BKK(n zMd({|%C+%$Pbd z^|RR9&{9?qQRA(ovdYo6RBE*-!*6hyd%6>;N_2SXg5j_e?yxOC86+c45h)XV8d}0f zx3g8^$Tl-{l_2B81Et@MuH=71lOtru%0A+*Ug2KcugIU1~ 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 diff --git a/back/uploads/2019/02/09/Supreme-logo-newyork-1920x1080.jpg b/back/uploads/2019/02/09/Supreme-logo-newyork-1920x1080.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f7922a6cec129f6af804a3336cd837f106beb7a GIT binary patch literal 76734 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
y7zrs!J*SH0ED=jAV1UQUxIMV9B2(zH|~qvR=b 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

X+mjvQz7cq+GAXQlIZMXJ zqLl>2T@(w9e5PmMQRkn7xcBX*?Gv!NULm_pZ~4(1TO~?GBxjJ|H`ngWcH*#k5+f^Z zFC#lM+EwPf%%5~bEsX{=CCLLbcN{d!&dI6&`bJ39x%SBK{}STblw^65pzE% zJ&wq<>ndz$qD9_OiM}!#PfkYjl}j8bSueeR^c`rJs)9#cnr(*2ez(3eW~W74a&s~L zQm}pd_a)(CYP0=JYDYIVHfe64tW#wFlADGo+2^?s&7R9zSw4V*)Zjj#6d7@Z5BX>^_HDZQ)(67#FpJ0a@)RN@&E9@)e1)Yz66 zj^VUp-ovj;c>`{`%s+mO4|ovJYXTYkT&=Zc4Hk0nEUsgrw;zURa9-rQkV{^vZ)6}} z$`|}}RMuC^;-3679DOuv8~YbdhA6?1oSa^=q)B1@>f z4R&^GkDFLsY^cblAEVeaebRX;Kik24<{{G1LtB}PDn4u(Xu4!!N`ix~ZV8&w)-0d7>BI!V(xC=Z zYbsQtR^}rjE)!CGZlI#*zQ5MC>u$UAPrdv7j(@oO!SC~V{ooG1-_QH~Zg8#=q$$CV z1aGV#vY2uM!OPHYo(-1LG{SK5Mxei{c=4j$E^2TWuJ!kQ$E=!IV~Oa>WP%7K2zXZ5 zk`_8s*43>qc(utEL#Y6tG^8OmT0;y~%ZaCh)e|EC&~7$gR1zWfr0^X2^ZTspe8w%U zw3kA-EBqg~XlR|#?O5OuMn0(ZK7wKov$)6H@7QLv1qoYmMLnum0vIMKSLl!r*{s|I zraDVZ4rq0fwTUr<*l_#Gnb6}DQOT;?P+kI=i9z;z9~qBbU_3&?%AAvY^;!z@$$v>f2yUY}W7Qra*^F%0P63??658|!YW_ng z^uyCd(&B>3c-Q7yy4|Wiekp3OuJ&#W!w9@=iB-TVdYFdDBGO})SsPnD8KtG~P9mW9 zGe4$5QDqpa==6EX@iECT$ON1SGvcn|2<^P!5(jbTmrgBn=&A9j66;$Fy8a?L3CaYs zxG4%(#LAQI06UH(Fmrm8u%j?1bURj=r5^h`vl$9jTCQc7_8E4Clz_$8Mx5{YLqj+; zwDp|9Kb1b}XIq?9wr8{--;UFz1#!LooDKX~FNH#?lGv*(Jt-`f(IaeVk#xPFGB)hE zwkdQ)FKvR9!+)f>8!~sHFfzuNo^ZP0+v55w-SlU0_Y`679Hckn=gR^nZ-nZN^fXUJi7j-t+C--3_vi_SPNN+kI&*@B?d;zt^#r5(U@lFM4NP z)BUL*=k#r8RJN!lXh@T{!W`Z6T~y?VA^z++^@%!$4t4wP2T)sxX4kSgJB4@Ptz3c2 z@l)717JG6;*caJT<9FxlR#Ed#aoeeISs*pbansujx#|7uj_>u+gd}0G;E*y| z;x8r_E2h5jbu8Qm`T{$|?_`g!0LJ)pg<1O{ymXxVc~6g!%Ppe!duABr*k?5SlR68yi={Gswm@ci3TIGFn;wctvmY>&Mgh zTJG4^kjNG*G5!{>j{1jy#f=;GI(yDLsgO@4?TpJv6Vk<8^H6;7)y3ZbTlGZ;GF>Zc zkKU8tt8125a5&LfCkLinti*d|Pi%&}y9&3^(w}ZyMki5b+7VI;yRE1#VIa=K)EzV3 zU^h)*4jCtAOd-tg_B4lMO-Ck2`nXO0^Jb5fAlkWMRF7Rn%xz*CuaBza*z7y=W@#03 zab literal 0 HcmV?d00001 From 7c472bb917c896fb527f27e3100ebd8ee3a8744d Mon Sep 17 00:00:00 2001 From: Rupika Date: Sat, 9 Feb 2019 13:41:39 -0800 Subject: [PATCH 30/32] moved the get_data_type and get_path_leaf to models.py from views.py to clean up --- back/backend/models.py | 31 +++++++++++++++++++++++++++++++ back/backend/views.py | 30 ++---------------------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/back/backend/models.py b/back/backend/models.py index b59c1ec..032ed0c 100644 --- a/back/backend/models.py +++ b/back/backend/models.py @@ -1,6 +1,7 @@ from django.db import models from django.conf import settings import datetime +import ntpath class Report(models.Model): user_id = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) @@ -38,6 +39,8 @@ class Field(models.Model): data_string = models.TextField(default='', blank=True) data_integer = models.IntegerField(default=0, blank=True) + # function that prints the string representation + # on the api? def __str__(self): if self.type == "boolean": if self.data_bool: @@ -54,3 +57,31 @@ class Field(models.Model): return "{}".format(self.data_string) elif self.type == "integer": return "{}".format(self.data_integer) + + + # function that gets corresponding + # data type + def get_datatype(self): + if self.type == "boolean": + if self.data_bool: + return True + else: + return False + elif self.type == "decimal": + return self.data_decimal + elif self.type == "date": + return "{}".format(self.data_date) + elif self.type == "file": + file_name = self.path_leaf(str(self.data_file)) + return "{}".format(file_name) + elif self.type == "string": + return "{}".format(self.data_string) + elif self.type == "integer": + return self.data_integer + + # function that accommodates if + # path has slash at end + def path_leaf(self, path): + head, tail = ntpath.split(path) + return tail or ntpath.basename(head) + diff --git a/back/backend/views.py b/back/backend/views.py index 1ddfa00..98cb155 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -50,8 +50,8 @@ def get_fields(s_id): queryset = Field.objects.filter(section_id=s_id).order_by('number') for i in queryset: - # function to print corresponding datatype - value = get_datatype(i) + # function that gets the corresponding datatype + value = Field.get_datatype(i) data = { "field_name": i.field_name, "label": i.label, @@ -65,32 +65,6 @@ def get_fields(s_id): return field_set -# function that gets corresponding -# data type -def get_datatype(self): - if self.type == "boolean": - if self.data_bool: - return True - else: - return False - elif self.type == "decimal": - return self.data_decimal - elif self.type == "date": - return "{}".format(self.data_date) - elif self.type == "file": - file_name = path_leaf(str(self.data_file)) - return "{}".format(file_name) - elif self.type == "string": - return "{}".format(self.data_string) - elif self.type == "integer": - return self.data_integer - -# function that accommodates if -# path has slash at end -def path_leaf(path): - head, tail = ntpath.split(path) - return tail or ntpath.basename(head) - # API Endpoints @api_view(['POST']) From d26b79c725815aa31ab651fb977cfc4462231525 Mon Sep 17 00:00:00 2001 From: kououken Date: Sat, 9 Feb 2019 14:00:49 -0800 Subject: [PATCH 31/32] Tweaked database so 'Super Report' is submitted with some complete sections, for testing. --- back/db.sqlite3 | Bin 99328 -> 100352 bytes front/static/js/viewHistory.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 9b7a3db3c49816018aeeb88b745028bf5b925f37..54ace4ab1c6d8615cfd6c75488c66d33d11c0990 100644 GIT binary patch delta 870 zcmaiyT}V@57{}lDeRj5;t(lV)vxqetZ8+EY-p+zz5mpyM6wysHzm7U{Zq6f`uySG_ zUS*vNBdEOS!WfEjq;(U9-sDC0aU(|Elou5gNEks7owK?S61w^E^6Z2N}f+n94yoU#{2v?vD{BR76lA(D? zG0lC0|@un=E)SlmMu^6-59xu6sHG8=fq|Muf7oAviRXNcH zf+b_BI0VQSQXo0v#Y;GWHVpTQKO;L(%pJ&4n8qB#%C!tv%lyeY5*4Ko%L-vBEQp%4 z?AOvGj*~%;w?j>Koo`ioTQZ5Xnn-nfjC~?f$hYLtG+S$=R?e@SWL8z;Pi#Fq)A$wwSi(l#)(mRP%LAO{iT;u?ZWA zOQs{RMH5U^;6tJ;vy#NIv3{jDl~guaN_+d7lL=K-TK}2~xj}rHcDRhqVzPk9f)VFq Y;vYWfr0Peg*#CZpJ~2gM_dmh^1`zS(CIA2c delta 309 zcmWlSze@sP9Eacge(uyuD~yVw1~DQdiPO4MMCb=${SgHA*Tk6KajFczL^GpWY#h8H~I9_ze29TbUllK73TZzleXFxAK(}uNb;`D)#<|6hFf| z%IE>3YciBuDJneVIu?~f3kUHvMYn%bistEXQjXz9J}qFFKFOw>Os2@rWt0v556CuJ AGynhq diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index f91b68d..6eae3cf 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -342,5 +342,5 @@ document.addEventListener("click", function(event) { const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid; getDataFromEndpoint(url, displayReport); } - // TODO: Add view report + // TODO: Add View Report }); From e315355e810a24a9c1013ebddb535e45df782f7d Mon Sep 17 00:00:00 2001 From: Rupika Date: Sat, 9 Feb 2019 15:32:15 -0800 Subject: [PATCH 32/32] fixing db --- back/db.sqlite3 | Bin 99328 -> 100352 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 239cbcc0f5b50c0b04d37c5a2d5929910d88c87d..54ace4ab1c6d8615cfd6c75488c66d33d11c0990 100644 GIT binary patch delta 1303 zcmah}ZA@EL7(VB`{iH1e3~U259UDRe)ce(2ZkK3KWHQq-Sam5$WzgQz-nJCl%jlXg zDbA0@C1adKjEOp#m5pUH4`5j%VpwD<9kQTo|?}PU=2Zp z+-EpBD>0QNQcJfBFH>IZbg^Skp|S_r8XNELpl)F&UE&pbgXd^OOuP7ij|+&Bm*ahs zVq6!+{sx7tA-DnG!WLYId2*4g(S~BTiF`!X>BGflW3>1r*=`1mElL%8D`@ps(bz0K zY6gYeq}GM3h5SN(BsY!vR*h^kfgLLq=&gX?_;s<~Wl_jk1iu^3r4@4efZaH|9Bnic z*n}4h=V}q^5DGL}QM+iz;=x%a2R-wymu{~0+q{Te!A0byyva?y?>R?uv7{mjB_*jA zvPu6DJ)`Hf8GpJ^RMSdO3uPju0c}*vq(-$qAs7w{Y?OkfkyI%BG>gTApcdpK;ekwu zWrc)cF4#}qTdlr$awt5Yg|eY!L`!O+LqTpdoE9V6NP0B8UyBHjb3@@_Arg)V!T#Yn zHcLbMf^=r986Tx5x7<{EzrS_AB5=IY!wEft;O6)M*BkKpy_`?rMZZxzcaqcs++s~a z6YvN82DjLqBxB&h8hBW&yM}>mW#BVamUeOp!EX2lo*-YrI=Mvtf@R1ug@r}syyzF=Y`tUuj*|G8U>Q2HT8#;mD2e<$`0Fh78349H= zp^qtV%Q?zTJvGQ?v+r7Tt(=;|?bt;RzmbHp=b@GHdAv$Le?4Ym0=&9Xdkj-squgz; zWUqgrVV|qnfo>zX%A|;bhx|;|Ntv|at2l*jGw!XOEyMw*Oltr?>@Xe%1`x z%kz?7_Deo0U+bjP$7>FByW5g_HZvAi3$c7^T4!&tEjm9RwUB3e?To4`dN(FX_WF8d z#m7t1KqfVr)ZK$qiCpJy-b3Gfv6&Iq`Yhy-ze3Rd)ZGXK!7E9u7)9W#es_bPeurtjT*A+p zEf_8%xXgO{7B~+ct3_#hi_L}xpIwl73r>Q#TZy@MsqW}N^ delta 863 zcmbV~T}V@57{}lDeRkZLo6($Kr5AIV8oKSAv+e9dsWi2uv3zc_=UHri_wIG!7|Vm}Uh<5J^E8byF8b&_xJd^nJ{ruDa;vxp;VZ{=fh8e-a}} ziPK3V+0-;b$bC+~2T$K>T2$g^<9ZtKsFCb3hpZ@LE3m0qP(Y5kn*&0~)9CdJK@Unu@6_3O$vOnM6+u0@B54>UQOHWeVkUQ1 z)Nw6Zr=DY74Ck^qOjh2`S)Jk#w_B{Y1X386&F*3yCdT2gTBH?=rD6+D77)CJ*YE;X zphwJz7w5oZcmRtq4-!nlb+`-{;XDk(85kf7Qd9gO5%(&xC<-v9rRA=23V5<6Didvz zHm8?JYyH|3+C|0@d?w>k^2iubCIKdeGWw0thI9(SG7L(Zi8zqbbn*UVskl5@LAwx{ z#c|{kS%qFS-PGjwmn2g)gH)M4$Orv#U+j1|%KBmq7Z9A@t`N`q!d73TRSG^=Vy)#b z!*;vV=8)o3LqtPhUA_w{hA*%#@8zYcr!!!XJG@dZHbt^rX|jsQD(rw)Z~*4WcNm2Y zA9qP!9@OA}i(9PHw^=2XMuQ5$8@LMh;1qbF5cY#g-tmcuAMT`Teh0D1Rj~MSV%vr+ zHXwKpGmr&{JR}T$A~%*qmcAw}UE*P^G=x=iKLVK2q|qb|!6TWg0d|p(WRCQaG>N6Z z;u}CoN_C(DaLuQ6EGfs0|EYdEt z3C3X97dD23&XeKxfRS}_Oq^vLjHxx^JKAk;Z^fb_OeO-8fq6yR@xDB{ac0?(%DTffmHMjcLzNz{KPdbG`!9;ZUteF{I~F;CE2xs@ HaJ1tm>^<`C