diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..182f34c --- /dev/null +++ b/.gitignore @@ -0,0 +1,122 @@ +Source: https://github.com/github/gitignore/blob/master/Python.gitignore + +# User generated +ENV/ +.vscode +.idea +.DS_Store +.history + + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class +.pytest_cache/ + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +.static_storage/ +.media/ +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# js +node_modules/ +.next/ + +# poetry +poetry.lock \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8f47e90 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +# Python version +FROM python:3 + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# Set work directory +WORKDIR /code + +# Install dependencies +COPY requirements.txt /code/ +RUN pip install -r requirements.txt + +# Copy project +COPY . /code/ \ No newline at end of file diff --git a/accounts/serializer.py b/accounts/serializer.py index 8873d1b..887c2fa 100644 --- a/accounts/serializer.py +++ b/accounts/serializer.py @@ -1,6 +1,8 @@ from django.db.models import fields from rest_framework import serializers from .models import Account +from rest_framework_simplejwt.serializers import TokenObtainPairSerializer + class AddSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True) @@ -31,4 +33,17 @@ class Meta: 'email','password','age','blood_type','phone_number','location', 'chronic_diseases','data','donate','group','image' ) - \ No newline at end of file + +class MyTokenObtainPairSerializer(TokenObtainPairSerializer): + def validate(self, attrs): + data = super().validate(attrs) + refresh = self.get_token(self.user) + data['refresh'] = str(refresh) + data['access'] = str(refresh.access_token) + + # Add extra responses here + data['id'] = self.user.id + data['username'] = self.user.username + + return data + diff --git a/accounts/urls.py b/accounts/urls.py index bc638f2..77507ce 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,9 +1,9 @@ from django.urls import path -from .views import AddListView,DetailAddView,ListView +from .views import AddListView,DetailAddView,ListView,CustomObtainAuthToken urlpatterns = [ - path('',AddListView.as_view(),name= 'add_data'), + path('signup',AddListView.as_view(),name= 'add_data'), path('',DetailAddView.as_view(),name = 'detail_data'), - # path('',DetailAddView.as_view(),name = 'detail_dataint'), + path("auth/", CustomObtainAuthToken.as_view()), path('view',ListView.as_view(),name = 'list_data') ] \ No newline at end of file diff --git a/accounts/views.py b/accounts/views.py index 54a1845..a72aab0 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,12 +1,16 @@ from django.shortcuts import render from rest_framework import generics, permissions -from .serializer import AddSerializer +from .serializer import AddSerializer,MyTokenObtainPairSerializer from .models import Account from rest_framework import permissions from django.shortcuts import get_object_or_404 +from rest_framework_simplejwt.views import TokenObtainPairView from .models import User # Create your views here. +class CustomObtainAuthToken(TokenObtainPairView): + serializer_class = MyTokenObtainPairSerializer + class AddListView(generics.CreateAPIView): serializer_class = AddSerializer queryset = Account.objects.all() diff --git a/api_tester.py b/api_tester.py new file mode 100644 index 0000000..782e8c6 --- /dev/null +++ b/api_tester.py @@ -0,0 +1,145 @@ +import fire +import requests + +API_HOST = "https://django34.herokuapp.com/" +RESOURCE_URI = "cookie_stands" +USERNAME = "yahialabib" +PASSWORD = "123123" + + +class ApiTester: + """CLI for testing API""" + + def __init__(self, host=API_HOST): + self.host = host + + def fetch_tokens(self): + """Fetches access and refresh JWT tokens from api + Returns: + tuple: access,refresh + """ + + token_url = f"{self.host}/api/token/" + + response = requests.post( + token_url, json={"username": USERNAME, "password": PASSWORD} + ) + + data = response.json() + + tokens = data["access"], data["refresh"] + + return tokens + + def get_all(self): + """get list of all resources from api + Usage: python api_tester.py get_all + Returns: JSON + """ + access_token = self.fetch_tokens()[0] + + url = f"{self.host}/api/all/" + + headers = { + "Authorization": f"Bearer {access_token}", + } + + response = requests.get(url, headers=headers) + + return response.json() + + def get_one(self, id): + """get 1 resource by id from api + Usage: + python api_tester.py get_one 1 + Returns: JSON + """ + access_token = self.fetch_tokens()[0] + + url = f"{self.host}/api/{id}" + + headers = { + "Authorization": f"Bearer {access_token}", + } + + response = requests.get(url, headers=headers) + + return response.json() + + # TODO adjust parameter names to match API + def create(self, name, description=None, owner=None): + """creates a resource in api + Usage: + python api_tester.py create / + --name=required --description=optional --owner=optional + Returns: JSON + """ + + access_token = self.fetch_tokens()[0] + + url = f"{self.host}/api/all" + + headers = { + "Authorization": f"Bearer {access_token}", + } + + data = { + "name": name, + "description": description, + "owner": owner, + } + + response = requests.post(url, json=data, headers=headers) + + return response.json() + + def update(self, id, name=None, description=None, owner=None): + """updates a resource in api + Usage: + python api_tester.py update 1 / + --name=optional --description=optional --owner=optional + Returns: JSON + """ + + access_token = self.fetch_tokens()[0] + + url = f"{self.host}/api/{id}/" + + headers = { + "Authorization": f"Bearer {access_token}", + } + + original = self.get_cookiestand(id) + + data = { + "name": name or original["name"], + "description": description or original["description"], + "owner": owner or original["owner"], + } + + response = requests.put(url, json=data, headers=headers) + + return response.text + + def delete(self, id): + """deletes a resource in api + Usage: + python api_tester.py delete 1 + Returns: Empty string if no error + """ + + access_token = self.fetch_tokens()[0] + + url = f"{self.host}/api/{id}/" + + headers = { + "Authorization": f"Bearer {access_token}", + } + + response = requests.delete(url, headers=headers) + + return response.text + + +if __name__ == "__main__": + fire.Fire(ApiTester) \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 index 8f3da34..79e3f53 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..19c83e0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: '4' + +services: + web: + build: . + command: gunicorn cookie_project.wsgi:application --bind 0.0.0.0:8000 --workers 4 + volumes: + - .:/code + ports: + - 8000:8000 \ No newline at end of file diff --git a/heroku.yml b/heroku.yml new file mode 100644 index 0000000..8f2bca6 --- /dev/null +++ b/heroku.yml @@ -0,0 +1,7 @@ +build: + docker: + web: Dockerfile +release: + image: web +run: + web: gunicorn cookie_project.wsgi --workers 4 \ No newline at end of file diff --git a/hospital/migrations/0003_alter_customuser_image.py b/hospital/migrations/0003_alter_customuser_image.py new file mode 100644 index 0000000..e6e0f89 --- /dev/null +++ b/hospital/migrations/0003_alter_customuser_image.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0 on 2021-12-30 19:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hospital', '0002_customuser_image'), + ] + + operations = [ + migrations.AlterField( + model_name='customuser', + name='image', + field=models.ImageField(upload_to='image'), + ), + ] diff --git a/hospital/migrations/0004_customuser_group.py b/hospital/migrations/0004_customuser_group.py new file mode 100644 index 0000000..35ef994 --- /dev/null +++ b/hospital/migrations/0004_customuser_group.py @@ -0,0 +1,21 @@ +# Generated by Django 4.0 on 2021-12-30 19:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ('hospital', '0003_alter_customuser_image'), + ] + + operations = [ + migrations.AddField( + model_name='customuser', + name='group', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='boes2', to='auth.group'), + preserve_default=False, + ), + ] diff --git a/hospital/migrations/__pycache__/0001_initial.cpython-39.pyc b/hospital/migrations/__pycache__/0001_initial.cpython-39.pyc index 61bfd28..961711a 100644 Binary files a/hospital/migrations/__pycache__/0001_initial.cpython-39.pyc and b/hospital/migrations/__pycache__/0001_initial.cpython-39.pyc differ diff --git a/hospital/migrations/__pycache__/0002_customuser_image.cpython-39.pyc b/hospital/migrations/__pycache__/0002_customuser_image.cpython-39.pyc index bed21d1..2892c46 100644 Binary files a/hospital/migrations/__pycache__/0002_customuser_image.cpython-39.pyc and b/hospital/migrations/__pycache__/0002_customuser_image.cpython-39.pyc differ diff --git a/hospital/migrations/__pycache__/__init__.cpython-39.pyc b/hospital/migrations/__pycache__/__init__.cpython-39.pyc index 7e30419..b52345e 100644 Binary files a/hospital/migrations/__pycache__/__init__.cpython-39.pyc and b/hospital/migrations/__pycache__/__init__.cpython-39.pyc differ diff --git a/hospital/models.py b/hospital/models.py index c1e3d72..d3f434b 100644 --- a/hospital/models.py +++ b/hospital/models.py @@ -1,7 +1,8 @@ from django.db import models -from django.contrib.auth.models import User +from django.contrib.auth.models import User,Group # Create your models here. class customUser (User): website = models.CharField(max_length=256) - image = models.ImageField(default='default.png') \ No newline at end of file + group = models.ForeignKey(Group, related_name="boes2", on_delete=models.CASCADE) + image = models.ImageField(upload_to = 'image') \ No newline at end of file diff --git a/hospital/serializers.py b/hospital/serializers.py index 0af7e24..5081dbc 100644 --- a/hospital/serializers.py +++ b/hospital/serializers.py @@ -1,3 +1,4 @@ +from django.contrib.auth.models import Group from rest_framework import serializers from django.contrib.auth import get_user_model # If used custom user model from .models import customUser @@ -14,6 +15,9 @@ def create(self, validated_data): username=validated_data['username'], password=validated_data['password'], website = validated_data['website'], + image = validated_data['image'], + group = validated_data['group'], + email = validated_data['email'], ) return user @@ -21,7 +25,7 @@ def create(self, validated_data): class Meta: model = customUser # Tuple of serialized model fields (see link [2]) - fields = ( "id", "username", "password", "website", "image" ) + fields = ( "id", "username", "password", "website", "image",'group','email' ) class MyTokenObtainPairSerializer(TokenObtainPairSerializer): diff --git a/hospital/urls.py b/hospital/urls.py index 3c54004..a388a64 100644 --- a/hospital/urls.py +++ b/hospital/urls.py @@ -4,7 +4,7 @@ from .views import CustomObtainAuthToken urlpatterns = [ - path('signup/', CreateUserView.as_view(), name='signup'), - path("/", HospitalDetail.as_view(), name="hospital_detail"), - path('authenticate/', CustomObtainAuthToken.as_view()) + path('signup', CreateUserView.as_view(), name='signup'), + path("", HospitalDetail.as_view(), name="hospital_detail"), + path("auth/", CustomObtainAuthToken.as_view()) ] \ No newline at end of file diff --git a/hospital/views.py b/hospital/views.py index 7cefef0..f9179f8 100644 --- a/hospital/views.py +++ b/hospital/views.py @@ -5,7 +5,7 @@ from .serializers import UserSerializer from rest_framework_simplejwt.views import TokenObtainPairView from .serializers import MyTokenObtainPairSerializer - +from django.shortcuts import get_object_or_404 @@ -24,4 +24,7 @@ class HospitalDetail(RetrieveAPIView): serializer_class = UserSerializer permission_classes = [ permissions.AllowAny # Or anon users can't register - ] \ No newline at end of file + ] + def get_object(self): + UserName= self.kwargs.get("username") + return get_object_or_404(customUser, username=UserName) \ No newline at end of file diff --git a/lifeshare/urls.py b/lifeshare/urls.py index 779470f..965af18 100644 --- a/lifeshare/urls.py +++ b/lifeshare/urls.py @@ -23,8 +23,8 @@ urlpatterns = [ path('admin/', admin.site.urls), - path('api/v1/add/',include('accounts.urls')), - path('api/token/', jwt_views.TokenObtainPairView.as_view(), name='token_obtain_pair'), + path('account/',include('accounts.urls')), + path('api/token/', jwt_views.TokenObtainPairView.as_view(), name='token_obtain_pair'), path('api/token/refresh/', jwt_views.TokenRefreshView.as_view(), name='token_refresh'), path('hospital/', include('hospital.urls')), ] diff --git a/templates/base.html b/templates/base.html deleted file mode 100644 index ec94dd0..0000000 --- a/templates/base.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - {% block title %}Django Auth Tutorial{% endblock %} - - -
- {% block content %} - {% endblock %} -
- - \ No newline at end of file diff --git a/templates/registration/signup.html b/templates/registration/signup.html deleted file mode 100644 index 404a990..0000000 --- a/templates/registration/signup.html +++ /dev/null @@ -1,13 +0,0 @@ - -{% extends 'base.html' %} - -{% block title %}Sign Up{% endblock %} - -{% block content %} -

Sign up

-
- {% csrf_token %} - {{ form.as_p }} - -
-{% endblock %} \ No newline at end of file diff --git a/views.py b/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here.