37
loading...
This website collects cookies to deliver better user experience
python -m venv env
source env/bin/activate
python -m venv env
env\scripts\activate
pip install django
django-admin startproject django_wallets
cd django_wallets
python manage.py startapp accounts && python manage.py startapp wallets
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'accounts.apps.AccountsConfig',
'wallets.apps.WalletsConfig'
]
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import gettext_lazy as _
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, **extra_fields):
if not email:
raise ValueError(_("email address cannot be left empty!"))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("is_active", True)
extra_fields.setdefault("user_type", 'ADMIN')
if extra_fields.get("is_staff") is not True:
raise ValueError(_("superuser must set is_staff to True"))
if extra_fields.get("is_superuser") is not True:
raise ValueError(_("superuser must set is_superuser to True"))
return self.create_user(email, password, **extra_fields)
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import gettext_lazy as _
from .manager import CustomUserManager
import uuid
class CustomUser(AbstractUser):
username = None
uid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(_("email address"), blank=False, unique=True)
first_name = models.CharField(_("first name"), max_length=150, blank=False)
last_name = models.CharField(_("last name"), max_length=150, blank=False)
date_of_birth = models.DateField(_("date of birth"), max_length=150, blank=False)
verified = models.BooleanField(_("verified"), default=False)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
AUTH_USER_MODEL = "accounts.CustomUser"
python manage.py makemigrations && python manage.py migrate
python manage.py runserver
from django import forms
from django.forms.widgets import PasswordInput, TextInput, EmailInput, FileInput, NumberInput
from .models import CustomUser
from .models import CustomUser
class UserRegistrationForm(forms.ModelForm):
password1 = forms.CharField(widget=PasswordInput(attrs={'class':'form-control', 'placeholder':'Password', 'required':'required'}))
password2 = forms.CharField(widget=PasswordInput(attrs={'class':'form-control', 'placeholder':'Confirm Password', 'required':'required'}))
class Meta:
model = CustomUser
fields = ('first_name','last_name','email','date_of_birth')
widgets = {
'first_name':TextInput(attrs={'class':'form-control', 'placeholder':'First Name', 'required':'required'}),
'last_name':TextInput(attrs={'class':'form-control', 'placeholder':'Last Name', 'required':'required'}),
'email': EmailInput(attrs={'class':'form-control', 'placeholder':'Email', 'required':'required'}),
'date_of_birth': DateInput(attrs={'class':'form-control', 'placeholder':'Date of Birth', 'required':'required','type': 'date'}),
}
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class CustomAuthForm(forms.Form):
email = forms.CharField(widget=EmailInput(attrs={'class':'form-control', 'placeholder':'Email', 'required':'required'}))
password = forms.CharField(widget=PasswordInput(attrs={'class':'form-control','placeholder':'Password', 'required':'required'}))
from django.shortcuts import render
from .forms import UserCreationForm
def register(request):
form = UserRegistrationForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
new_user = form.save()
return redirect('accounts:register')
return render(request, "accounts/register.html", context = {"form":form})
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
from django.urls import path
from .views import register
app_name = "accounts"
urlpatterns = [
path('register/', register, name="register"),
]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('account/', include('accounts.urls', namespace='accounts'))
]
def login_user(request):
form = CustomAuthForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
cd = form.cleaned_data
user = authenticate(request, email = cd['email'], password=cd['password'])
if user is not None:
login(request, user)
return redirect('accounts:dashboard')
else:
messages.error(request, 'Account does not exist')
return render(request, "accounts/login.html", context = {"form":form})
@login_required
def dashboard(request):
return render(request, "dashboard.html", context={})
urlpatterns = [
path('register/', register, name="register"),
path('login/', login_user, name="login"),
path('', dashboard, name="dashboard"),
]
def register(request):
form = UserRegistrationForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
new_user = form.save()
messages.success(request, 'Account succesfully created. You can now login')
return redirect('accounts:login')
return render(request, "accounts/register.html", context = {"form":form})
from django.db import models, transaction
from django.utils.translation import gettext_lazy as _
from accounts.models import CustomUser
import uuid
class Wallet(models.Model):
uid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.OneToOneField(CustomUser, on_delete=models.SET_NULL, null=True)
balance = models.DecimalField(_("balance"), max_digits=100, decimal_places=2)
account_name = models.CharField(_("account name"), max_length=250)
account_number = models.CharField(_("account number"), max_length=100)
bank = models.CharField(_("bank"), max_length=100)
phone_number = models.CharField(_("phone number"), max_length=15)
password = models.CharField(_("password"), max_length=200)
created = models.DateTimeField(auto_now_add=True)
class BVNForm(forms.Form):
bvn = forms.CharField(widget=NumberInput(attrs={'class':'form-control', 'placeholder':'Your BVN', 'required':'required'}))
from wallets.api import WalletsClient
from wallets.models import Wallet
from cryptography.fernet import Fernet
wallet = WalletsClient(secret_key="hfucj5jatq8h", public_key="uvjqzm5xl6bw")
fernet = Fernet(settings.ENCRYPTION_KEY)
@login_required
def create_wallet(request):
form = BVNForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
cd = form.cleaned_data
user = request.user
bvn = cd["bvn"]
new_wallet = wallet.create_user_wallet(
first_name= user.first_name,
last_name= user.last_name,
email=user.email,
date_of_birth= user.date_of_birth.strftime('%Y-%m-%d'),
bvn= str(bvn)
)
if new_wallet["response"]["responseCode"] == '200':
user.verified = True
user.save()
Wallet.objects.create(
user = user,
balance = new_wallet["data"]["availableBalance"],
account_name = new_wallet["data"]["accountName"],
account_number = new_wallet["data"]["accountNumber"],
bank = new_wallet["data"]["bank"],
phone_number = new_wallet["data"]["phoneNumber"],
password = fernet.encrypt(new_wallet["data"]["password"].encode())
)
messages.success(request, "Account verified, wallet successfully created")
return redirect("accounts:dashboard")
else:
messages.error(request, new_wallet["response"]["message"])
return render(request, "accounts/bvn.html", context = {"form":form})
from cryptography.fernet import Fernet
key = Fernet.generate_key()
ENCRYPTION_KEY = key
from functools import wraps
from django.shortcuts import redirect
from django.contrib import messages
def verified(function):
@wraps(function)
def wrap(request, *args, **kwargs):
if request.user.verified:
return function(request, *args, **kwargs)
else:
messages.error(request, "Your account hasn't been verified")
return redirect("accounts:verify")
return wrap
from .decorators import verified
@login_required
@verified
def dashboard(request):
wallet = get_object_or_404(Wallet, user=request.user)
return render(request, "dashboard.html", context={"wallet":wallet})
@login_required
def logout_user(request):
logout(request)
return redirect("accounts:login")
urlpatterns = [
...
path('logout/', logout_user, name="logout"),
]
class WalletTransaction(models.Model):
class STATUS(models.TextChoices):
PENDING = 'pending', _('Pending')
SUCCESS = 'success', _('Success')
FAIL = 'fail', _('Fail')
class TransactionType(models.TextChoices):
BANK_TRANSFER_FUNDING = 'funding', _('Bank Transfer Funding')
BANK_TRANSFER_PAYOUT = 'payout', _('Bank Transfer Payout')
DEBIT_USER_WALLET = 'debit user wallet', _('Debit User Wallet')
CREDIT_USER_WALLET = 'credit user wallet', _('Credit User Wallet')
transaction_id = models.CharField(_("transaction id"), max_length=250)
status = models.CharField(max_length=200, null=True,
choices=STATUS.choices,
default=STATUS.PENDING
)
transaction_type = models.CharField(max_length=200, null=True,
choices=TransactionType.choices
)
wallet = models.ForeignKey(Wallet, on_delete=models.SET_NULL,
null=True
)
amount = models.DecimalField(_("amount"), max_digits=100, decimal_places=2)
date = models.CharField(_("date"), max_length=200)
from django.db import transaction
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import render, get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from ipaddress import ip_address, ip_network
import json
from .models import Wallet, WalletTransaction
@csrf_exempt
@require_POST
def webhook(request):
whitelist_ip = "18.158.59.198"
forwarded_for = u'{}'.format(request.META.get('HTTP_X_FORWARDED_FOR'))
client_ip_address = ip_address(forwarded_for)
if client_ip_address != ip_network(whitelist_ip):
return HttpResponseForbidden('Permission denied.')
payload = json.loads(request.body)
if payload['EventType'] == "BankTransferFunding":
wallet = get_object_or_404(Wallet, phone_number = payload["phoneNumber"])
wallet.balance += payload["amount"]
wallet.save()
transaction = WalletTransaction.objects.create(
transaction_id = payload["transactionRef"],
transaction_type = "funding",
wallet = wallet,
status = "success",
amount = payload["amount"],
date = payload["DateCredited"]
)
else:
pass
return HttpResponse(status=200)
from django.urls import path
from .views import webhook
urlpatterns = [
path(
"webhooks/wallets_africa/aDshFhJjmIalgxCmXSj/",
webhook,
name = "webhook"
),
]