Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
irfanpule committed Feb 6, 2018
0 parents commit 26d1fd5
Show file tree
Hide file tree
Showing 33 changed files with 459 additions and 0 deletions.
Empty file added academy/__init__.py
Empty file.
Binary file added academy/__pycache__/__init__.cpython-36.pyc
Binary file not shown.
Binary file added academy/__pycache__/settings.cpython-36.pyc
Binary file not shown.
Binary file added academy/__pycache__/urls.cpython-36.pyc
Binary file not shown.
Binary file added academy/__pycache__/wsgi.cpython-36.pyc
Binary file not shown.
Empty file added academy/apps/__init__.py
Empty file.
Binary file added academy/apps/__pycache__/__init__.cpython-36.pyc
Binary file not shown.
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
26 changes: 26 additions & 0 deletions academy/apps/accounts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from .models import User, Profile


class UserAdmin(DjangoUserAdmin):
fieldsets = (
(None, {'fields': ('email', 'username', 'password')}),
('Personal Info', {'fields': ('first_name', 'last_name', 'phone')}),
('Permissions', {'fields': (
'role', 'is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions',)}),
('Important dates', {'fields': ('last_login', 'date_joined')}),
)

list_display = ('username', 'email', 'is_staff')


class UserProfile(admin.ModelAdmin):
search_fields = ('user__username',)


admin.site.register(User, UserAdmin)
admin.site.register(Profile, UserProfile)
8 changes: 8 additions & 0 deletions academy/apps/accounts/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.apps import AppConfig


class AccountsConfig(AppConfig):
name = 'accounts'
63 changes: 63 additions & 0 deletions academy/apps/accounts/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-02-06 23:34
from __future__ import unicode_literals

import academy.apps.accounts.models
import academy.core.validators
from django.conf import settings
import django.contrib.auth.validators
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone


class Migration(migrations.Migration):

initial = True

dependencies = [
('auth', '0008_alter_user_username_max_length'),
]

operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(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')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('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')),
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=30, 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')),
('email', models.EmailField(max_length=254, null=True, unique=True)),
('phone', models.CharField(blank=True, default=None, max_length=30, null=True, validators=[academy.core.validators.validate_mobile_phone])),
('role', models.PositiveIntegerField(blank=True, choices=[(1, 'Student'), (2, 'Trainer'), (2, 'Company')], null=True)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', academy.apps.accounts.models.CustomUserManager()),
],
),
migrations.CreateModel(
name='Profile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('address', models.TextField()),
('gender', models.PositiveIntegerField(blank=True, choices=[(1, 'Male'), (2, 'Female')], null=True)),
('birthday', models.DateField(blank=True, null=True)),
('organization_name', models.CharField(blank=True, max_length=200, null=True)),
('avatar', models.ImageField(blank=True, null=True, upload_to='images/avatar/%Y/%m/%d')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
],
),
]
Empty file.
Binary file not shown.
Binary file not shown.
55 changes: 55 additions & 0 deletions academy/apps/accounts/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.contrib.auth.models import AbstractUser, UserManager

from academy.core.utils import image_upload_path
from academy.core.validators import validate_mobile_phone

from model_utils import Choices


class CustomUserManager(UserManager):
def create_user(self, username, email, password, is_active=False, **extra_fields):
user = super().create_user(username, email, password, is_active=False, **extra_fields)
return user


class User(AbstractUser):
email = models.EmailField(unique=True, null=True)
phone = models.CharField(max_length=30, blank=True, null=True, default=None,
validators=[validate_mobile_phone])
ROLE = Choices(
(1, 'student', 'Student'),
(2, 'trainer', 'Trainer'),
(2, 'company', 'Company'),
)
role = models.PositiveIntegerField(choices=ROLE, blank=True, null=True)

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = CustomUserManager()

@property
def name(self):
name = self.get_full_name()
if not name:
name = self.username
return name


class Profile(models.Model):
user = models.OneToOneField('accounts.User', related_name='profile')
address = models.TextField()
GENDER = Choices(
(1, 'male', 'Male'),
(2, 'female', 'Female'),
)
gender = models.PositiveIntegerField(choices=GENDER, blank=True, null=True)
birthday = models.DateField(blank=True, null=True)
organization_name = models.CharField(max_length=200, blank=True, null=True)
avatar = models.ImageField(upload_to=image_upload_path('avatar'), blank=True, null=True)

def __str__(self):
return self.user.username
6 changes: 6 additions & 0 deletions academy/apps/accounts/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render

# Create your views here.
Empty file added academy/core/__init__.py
Empty file.
Binary file added academy/core/__pycache__/__init__.cpython-36.pyc
Binary file not shown.
Binary file added academy/core/__pycache__/custom_auth.cpython-36.pyc
Binary file not shown.
Binary file added academy/core/__pycache__/utils.cpython-36.pyc
Binary file not shown.
Binary file not shown.
26 changes: 26 additions & 0 deletions academy/core/custom_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from django.contrib.auth.backends import ModelBackend

from django.conf import settings
from django.contrib.auth import get_user_model


class EmailBackend(ModelBackend):
# Authenticate user using email

def authenticate(self, username=None, password=None):
if '@' in username:
kwargs = {'email': username}
else:
kwargs = {'username': username}
try:
user = get_user_model().objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None

def get_user(self, username):
try:
return get_user_model().objects.get(pk=username)
except get_user_model().DoesNotExist:
return None
3 changes: 3 additions & 0 deletions academy/core/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def image_upload_path(prefix='etc'):
path = f"images/{prefix}/%Y/%m/%d"
return path
69 changes: 69 additions & 0 deletions academy/core/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import phonenumbers
from phonenumbers import phonenumberutil
from id_phonenumbers import parse

from django.conf import settings
from django.core.validators import validate_email as django_validate_email
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext
from django.contrib.auth.password_validation import (MinimumLengthValidator as DjangoMinimumLengthValidator,
NumericPasswordValidator as DjangoNumericPasswordValidator)


def validate_email(email):
return validate_email_address(email)

def validate_email_address(email):
try:
django_validate_email(email)
except ValidationError:
raise ValidationError(f'{email} is not a valid email', code='invalid')

if email.endswith('.'):
raise ValidationError('Email cannot end with \'.\' (dot), please check again')
else:
return True

def validate_mobile_phone(phone_number):
# Indonesia only accept mobile phone
if settings.COUNTRY == 'ID':
try:
number = parse(phone_number)
except phonenumberutil.NumberParseException:
raise ValidationError('Please enter a valid mobile phone number.')

if number.is_mobile:
return True

# International phone numbers are accepted
if phone_number.startswith('+') and len(phone_number) > 8:
return True
else:
try:
phone = phonenumbers.parse(phone_number, settings.COUNTRY)
except phonenumberutil.NumberParseException:
raise ValidationError('Please enter a valid mobile phone number.')
number_type = phonenumberutil.number_type(phone)

accepted_mobile_type = [
phonenumberutil.PhoneNumberType.MOBILE,
phonenumberutil.PhoneNumberType.FIXED_LINE_OR_MOBILE,
]

if number_type in accepted_mobile_type:
return True

raise ValidationError('Please enter a valid mobile phone number.')


class MinimumLengthValidator(DjangoMinimumLengthValidator):
def get_help_text(self):
return ugettext(
"Password must contain at least %(min_length)d characters."
% {'min_length': self.min_length}
)


class NumericPasswordValidator(DjangoNumericPasswordValidator):
def get_help_text(self):
return ugettext("Password can't be entirely numeric.")
Loading

0 comments on commit 26d1fd5

Please sign in to comment.