Merge branch 'master' into ViewReport
This commit is contained in:
		
						commit
						4ed0b26811
					
				
					 20 changed files with 348 additions and 137 deletions
				
			
		|  | @ -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" | ||||
|  |  | |||
							
								
								
									
										72
									
								
								back/Pipfile.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										72
									
								
								back/Pipfile.lock
									
										
									
										generated
									
									
									
								
							|  | @ -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": {} | ||||
|  |  | |||
							
								
								
									
										18
									
								
								back/backend/migrations/0005_field_field_name.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								back/backend/migrations/0005_field_field_name.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -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), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -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) | ||||
|  |  | |||
|  | @ -1,10 +1,37 @@ | |||
| # 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 +39,7 @@ general_section = Section( | |||
|     title="General Info", | ||||
|     html_description="", | ||||
|     fields={ | ||||
|         "destination": {"label": "Destination City", "type": "string"} | ||||
|         "destination": {"label": "Destination City", "type": "string"}, | ||||
|     } | ||||
| ) | ||||
| 
 | ||||
|  | @ -22,7 +49,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 | ||||
|  | @ -34,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"}, | ||||
|     } | ||||
| ) | ||||
| 
 | ||||
|  | @ -43,13 +71,14 @@ 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 | ||||
| lodging_section = Section( | ||||
|     title="Hotel Info", | ||||
|     html_description="<p>Enter hotel info here.\nPer diem rates can be found at <a href='https://www.gsa.gov/travel/plan-book/per-diem-rates'></a></p>", | ||||
|     html_description="<p>Enter hotel info here.\nPer diem rates can be found at " | ||||
|                      "<a href='https://www.gsa.gov/travel/plan-book/per-diem-rates'></a></p>", | ||||
|     fields={ | ||||
|         "check-in_date": {"label": "Check-in date", "type": "date"}, | ||||
|         "check-out_date": {"label": "Check-out date", "type": "date"}, | ||||
|  | @ -64,13 +93,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 +118,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 +138,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="<p></p>", | ||||
|     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) | ||||
|  |  | |||
							
								
								
									
										3
									
								
								back/backend/test.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								back/backend/test.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| from policy import pol | ||||
| 
 | ||||
| print(pol) | ||||
|  | @ -1,6 +1,7 @@ | |||
| from rest_framework.decorators import api_view | ||||
| from django.http import JsonResponse | ||||
| from .models import * | ||||
| from .policy import pol | ||||
| 
 | ||||
| 
 | ||||
| # function that prints all the reports | ||||
|  | @ -47,15 +48,17 @@ 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: | ||||
|         # function to print corresponding datatype | ||||
|         value = get_datatype(i) | ||||
|         data = { | ||||
|             "field_name": "TODO", | ||||
|             "field_name": i.field_name, | ||||
|             "label": i.label, | ||||
|             "type": i.type, | ||||
|             "number": i.number, | ||||
|             "value": "get_value", | ||||
|             "value": 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 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": | ||||
|         return "{}".format(self.data_file) | ||||
|     elif self.type == "string": | ||||
|         return "{}".format(self.data_string) | ||||
|     elif self.type == "integer": | ||||
|         return self.data_integer | ||||
| 
 | ||||
| 
 | ||||
| # API Endpoints | ||||
| @api_view(['POST']) | ||||
|  | @ -70,75 +96,37 @@ 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": "<p>Enter flight details here.</p>", | ||||
|                 "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": "<p>If you used a hotel, please enter the details.</p>", | ||||
|                 "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().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, | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								back/db.sqlite3
									
										
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								back/db.sqlite3
									
										
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -39,10 +39,15 @@ INSTALLED_APPS = [ | |||
|     'django.contrib.sessions', | ||||
|     'django.contrib.messages', | ||||
|     'django.contrib.staticfiles', | ||||
|     'django.contrib.sites', | ||||
| # 3rd party | ||||
|     'rest_framework', | ||||
|     'rest_framework.authtoken', | ||||
|     'allauth', | ||||
|     'allauth.account', | ||||
|     'allauth.socialaccount', | ||||
|     'rest_auth', | ||||
|     'rest_auth.registration', | ||||
|     'corsheaders', | ||||
| # local | ||||
|     'users', | ||||
|  | @ -149,3 +154,25 @@ 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 | ||||
| 
 | ||||
| # Registration | ||||
| 
 | ||||
| #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', | ||||
| } | ||||
| 
 | ||||
| AUTHENTICATION_BACKENDS = ( | ||||
|     'django.contrib.auth.backends.ModelBackend', | ||||
|     'allauth.account.auth_backends.AuthenticationBackend', | ||||
| ) | ||||
|  |  | |||
|  | @ -13,5 +13,7 @@ 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/v1/account/register/', NameRegistrationView.as_view()), | ||||
|     path('api-auth/', include('rest_framework.urls')), | ||||
| ] | ||||
|  |  | |||
							
								
								
									
										47
									
								
								back/users/serializers.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								back/users/serializers.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
|  | @ -1,3 +1 @@ | |||
| from django.shortcuts import render | ||||
| 
 | ||||
| # Create your views here. | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ | |||
|             </ul> | ||||
|         </div> | ||||
|     </nav> | ||||
|     <div class="container pt-5"> | ||||
|     <div class="container pt-3"> | ||||
|         <div class="row"> | ||||
|             <div class="col-sm-8 mx-auto"> | ||||
|                 <div class="card bg-light text-dark"> | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ | |||
|             </ul> | ||||
|         </div> | ||||
|     </nav> | ||||
|     <div class="container"> | ||||
|     <div class="container pt-3"> | ||||
|         <p>Welcome to Reimbursinator</p> | ||||
|     </div> | ||||
|     <script src="js/logout.js"></script> | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ | |||
|             </ul> | ||||
|         </div> | ||||
|     </nav> | ||||
|     <div class="container"> | ||||
|     <div class="container pt-3"> | ||||
|         <div class="jumbotron"> | ||||
|             <h1>Reimbursinator</h1> | ||||
|             <p class="lead">An open source expense management solution sponsored by the Software Freedom Conservancy</p> | ||||
|  |  | |||
|  | @ -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/"; | ||||
|  |  | |||
|  | @ -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(''); | ||||
| } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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("REGISTRATION 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); | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ | |||
|     <nav class="navbar navbar-expand-sm navbar-dark bg-primary"> | ||||
|         <div class="navbar-brand">Reimbursinator</div> | ||||
|     </nav> | ||||
|     <div class="container pt-5"> | ||||
|     <div class="container pt-3"> | ||||
|         <div class="row"> | ||||
|             <div class="col-sm-6 mx-auto"> | ||||
|                 <div class="card bg-light text-dark"> | ||||
|  | @ -24,12 +24,12 @@ | |||
|                     <div class="card-body"> | ||||
|                         <form class="form" autocomplete="off"> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="formGroupUsername">Username:</label> | ||||
|                                 <input class="form-control" id="formGroupUsername" type="text" name="username" required autofocus> | ||||
|                                 <label for="email">Email:</label> | ||||
|                                 <input class="form-control" id="email" type="email" name="email" required> | ||||
|                             </div> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="formGroupPassword">Password:</label> | ||||
|                                 <input class="form-control" id="formGroupPassword" type="password" name="password" required> | ||||
|                                 <label for="password">Password:</label> | ||||
|                                 <input class="form-control" id="password" type="password" name="password" required> | ||||
|                             </div> | ||||
|                             <p id="errorLogin" style="color:red"></p> | ||||
|                             <button type="submit" class="btn btn-primary pull-right">Submit</button> | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ | |||
|             </ul> | ||||
|         </div> | ||||
|     </nav> | ||||
|     <div class="container"> | ||||
|     <div class="container pt-3"> | ||||
|         <p>Create a new report</p> | ||||
|     </div> | ||||
|     <script src="js/logout.js"></script> | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ | |||
|     <nav class="navbar navbar-expand-sm navbar-dark bg-primary"> | ||||
|         <div class="navbar-brand">Reimbursinator</div> | ||||
|     </nav> | ||||
|     <div class="container pt-5"> | ||||
|     <div class="container pt-3"> | ||||
|         <div class="row"> | ||||
|             <div class="col-sm-6 mx-auto"> | ||||
|                 <div class="card bg-light text-dark"> | ||||
|  | @ -23,21 +23,25 @@ | |||
|                     </div> | ||||
|                     <div class="card-body"> | ||||
|                         <form class="form signup" autocomplete="off" action="index.html"> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="userName">Username:</label> | ||||
|                                 <input class="form-control" id="userName" type="text" name="username" minlength="4" size="10" required autofocus> | ||||
|                             </div> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="email">Email:</label> | ||||
|                                 <input class="form-control" type="email" id="email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$" oninput="validateEmail(this);" required> | ||||
|                             </div> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="password">Password:</label> | ||||
|                                 <input class="form-control" type="password" id="password" minlength="4" size="10" required> | ||||
|                                 <label for="first_name">First Name:</label> | ||||
|                                 <input class="form-control" id="first_name" type="text" name="first_name" required> | ||||
|                             </div> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="confirmPassword">Confirm Password:</label> | ||||
|                                 <input class="form-control" type="password" id="confirmPassword" required> | ||||
|                                 <label for="last_name">Last Name:</label> | ||||
|                                 <input class="form-control" id="last_name" type="text" name="last_name" required> | ||||
|                             </div> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="password1">Password:</label> | ||||
|                                 <input class="form-control" type="password" id="password1" name="password1" minlength="8" required> | ||||
|                             </div> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="password2">Confirm Password:</label> | ||||
|                                 <input class="form-control" type="password" id="password2" name="password2" minlength="8" required> | ||||
|                             </div> | ||||
|                             <button type="submit" class="btn btn-primary">Submit</button> | ||||
|                         </form> | ||||
|  | @ -51,5 +55,4 @@ | |||
|     </div> | ||||
| </body> | ||||
| <script src="js/signupPage.js"></script> | ||||
|     <!--Still need to check if user exist and if email exist test--> | ||||
| </html> | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Jack
						Jack