Skip to content

Commit

Permalink
Merge pull request #33 from jamedadi/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
MrMohammadY authored Oct 26, 2021
2 parents 575c763 + 6d32626 commit 221e86a
Show file tree
Hide file tree
Showing 173 changed files with 5,269 additions and 1 deletion.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
__pycache__/
*.py[cod]
*$py.class

media/
# C extensions
*.so

Expand Down Expand Up @@ -54,6 +54,7 @@ coverage.xml
# Translations
*.mo
*.pot
.idea/

# Django stuff:
*.log
Expand Down Expand Up @@ -127,3 +128,6 @@ dmypy.json

# Pyre type checker
.pyre/

# media
media/
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,48 @@
Yummy
---
**This project is going to be a clone of sanpp food with Python and Django framework.**

---

## What is yummy?

It’s actually a service which users can order food very easily and restaurant managers can register their services so
that other people can use them.

As I said this is going to be a clone of this service , clearly It’s not going to implement all the features

---

## The goal of this project:

The main purpose of this project is being an acceptable resume and also a good practice of Django framework

---

## Features:

- [x] We will have two type of users in this project : 1 - Customer 2 - Service Provider.
- [x] Each service provider can provide different services such as (restaurant, fast food, confectionery, supermarket,
…).
- [x] Each service will be able to have a menu containing different items.
- [x] Each service will be able to have custom categories for the items of the menu.
- [x] Each service provider must specify the supported areas for the item delivery for the service.
- [ ] Each service provider can add discount on some of their items for a limited time.
- [x] Each service will have active days and hours.
- [x] Each customer can have different addresses.
- [x] Each customer will be able to see the services(only the supported services in their area).
- [x] Each customer can add items to their cart(note : Each cart can only contain items from one specific service, that
means adding items from different services causes multiple carts).
- [ ] Each customer will be able to add comment for the items which was in their cart after the order was delivered(
note: customers will be able to add one comment for an item after each successful order).
- [ ] Each item will have a score based on its comments.
- [x] Each user will be to see the status of the order after the payment has been successful.
- [ ] The quantity of each item must be increased and decreased at successful orders.

---

## Architecture of the project:

The project is based on the MVT architecture of the Django framework, so we will use SSR(server side rendering)

---
Empty file added accounts/__init__.py
Empty file.
22 changes: 22 additions & 0 deletions accounts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.contrib import admin
from django.contrib.auth.hashers import make_password

from accounts.models import Customer, ServiceProvider


@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
list_display = ('phone_number', 'first_name', 'last_name', 'date_joined', 'is_active')
list_filter = ('is_active', 'date_joined')
search_fields = ('phone_number',)

def save_model(self, request, obj, form, change):
obj.password = make_password(form.cleaned_data['password'])
return super().save_model(request, obj, form, change)


@admin.register(ServiceProvider)
class ServiceProviderAdmin(admin.ModelAdmin):
list_display = ('username', 'email', 'phone_number', 'date_joined', 'is_active')
list_filter = ('is_active', 'date_joined')
search_fields = ('username', 'phone_number')
6 changes: 6 additions & 0 deletions accounts/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class AccountsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'accounts'
42 changes: 42 additions & 0 deletions accounts/authenticate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from django.contrib.auth.backends import BaseBackend

from accounts.models import Customer, ServiceProvider


class PhoneNumberPasswordBackend(BaseBackend):
def authenticate(self, request, phone_number=None, password=None):
try:
customer = Customer.objects.get(phone_number=phone_number)
except Customer.DoesNotExist:
return None
else:
if password: # if the password is sent via the form
if customer.check_password(password):
return customer
else:
return None
return customer

def get_user(self, user_id):
try:
customer = Customer.objects.get(pk=user_id)
except Customer.DoesNotExist:
return None
else:
return customer


class ServiceProviderAuthentication(BaseBackend):
def authenticate(self, request, username=None, password=None):
try:
user = ServiceProvider.objects.get(username=username, password=password)
return user

except ServiceProvider.DoesNotExist:
return None

def get_user(self, user_id):
try:
return ServiceProvider.objects.get(pk=user_id)
except ServiceProvider.DoesNotExist:
return None
166 changes: 166 additions & 0 deletions accounts/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
from django import forms
from django.contrib.auth import password_validation
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.core.validators import int_list_validator
from django.utils.translation import gettext_lazy as _

from accounts.models import ServiceProvider, Customer
from accounts.utils import phone_number_validator


class CustomerLoginRegisterForm(forms.Form):
phone_number = forms.CharField(max_length=12,
validators=[
int_list_validator(message=_('only digits are accepted')),
phone_number_validator
],
widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'phone number'})
)


class CustomerCodeConfirmForm(forms.Form):
code = forms.CharField(
validators=[int_list_validator(message=_('only digits are accepted'))],
widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': _('confirmation code')
}
)
)


class CustomerPasswordForm(forms.Form):
password = forms.CharField(
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
'placeholder': _('password')
}
)
)


class CustomerPasswordSetForm(forms.ModelForm):
error_messages = {
'password_mismatch': _('The two password fields didn’t match.'),
}
password = forms.CharField(
label=_("Password"),
strip=False,
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
help_text=password_validation.password_validators_help_text_html(),
)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
strip=False,
help_text=_("Enter the same password as before, for verification."),
)

class Meta:
model = Customer
fields = ('password',)

def clean_password2(self):
password = self.cleaned_data.get("password")
password2 = self.cleaned_data.get("password2")
if password and password2 and password != password2:
raise ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2

def save(self, commit=True):
customer = super().save(commit=False)
customer.set_password(self.cleaned_data["password"])
if commit:
customer.save()
return customer


class CustomerProfileUpdateForm(forms.ModelForm):
class Meta:
model = Customer
fields = ('first_name', 'last_name')


class ServiceProviderRegistrationForm(forms.ModelForm):
username = forms.CharField(
max_length=30,
min_length=4,
widget=forms.TextInput(
attrs={
'placeholder': 'Username',
'class': 'form-control'}
)
)
phone_number = forms.CharField(max_length=12,
validators=[
int_list_validator(message=_('only digits are accepted')),
phone_number_validator
],
widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'phone number'})
)
confirm_password = forms.CharField(
widget=forms.PasswordInput(
attrs={
'placeholder': 'Confirm Password',
'class': 'form-control'}
)
)

class Meta:
model = ServiceProvider
fields = ('username', 'email', 'phone_number', 'password', 'confirm_password')
widgets = {
'email': forms.EmailInput(attrs={'placeholder': 'Email', 'class': 'form-control'}),
'phone_number': forms.TextInput(attrs={'placeholder': 'Phone Number', 'class': 'form-control'}),
'password': forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}),
}

def clean_confirm_password(self):
if self.cleaned_data['password'] != self.cleaned_data['confirm_password']:
raise ValidationError('passwords not equal!')
return self.cleaned_data['confirm_password']


class ServiceProviderLoginForm(forms.Form):
username = forms.CharField(
min_length=4,
widget=forms.TextInput(
attrs={
'placeholder': 'Username, Email, Phone Number',
'class': 'form-control'}
)
)

password = forms.CharField(
max_length=30,
min_length=4,
widget=forms.PasswordInput(
attrs={
'placeholder': 'Password',
'class': 'form-control'}
)
)

def clean(self):
cleaned_data = super().clean()

username = cleaned_data['username']
user = ServiceProvider.objects.filter(
Q(username=username) |
Q(email=username) |
Q(phone_number=username),
).first()

if user and user.check_password(cleaned_data['password']):
cleaned_data['user'] = user
return cleaned_data

raise ValidationError('username or password invalid!')
62 changes: 62 additions & 0 deletions accounts/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Generated by Django 3.2 on 2021-08-28 20:31

import accounts.models
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.utils.timezone


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='Customer',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('phone_number', models.CharField(max_length=13, unique=True, verbose_name='phone number')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
],
options={
'verbose_name': 'Customer',
'verbose_name_plural': 'Customers',
'db_table': 'customer',
},
managers=[
('objects', accounts.models.CustomerManager()),
],
),
migrations.CreateModel(
name='ServiceProvider',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('email', models.EmailField(blank=True, max_length=254, unique=True, verbose_name='email address')),
('phone_number', models.CharField(max_length=13, unique=True, verbose_name='phone number')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
],
options={
'verbose_name': 'Service provider',
'verbose_name_plural': 'Service providers',
'db_table': 'service_provider',
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]
Loading

0 comments on commit 221e86a

Please sign in to comment.