| @@ -1,6 +1,6 @@ | |||||
| from django.apps import AppConfig | from django.apps import AppConfig | ||||
| class UserConfig(AppConfig): | |||||
| class AccountsConfig(AppConfig): | |||||
| default_auto_field = 'django.db.models.BigAutoField' | default_auto_field = 'django.db.models.BigAutoField' | ||||
| name = 'user' | |||||
| name = 'accounts' | |||||
| @@ -0,0 +1,7 @@ | |||||
| from django import forms | |||||
| from .models import Account | |||||
| class AccountForm(forms.ModelForm): | |||||
| class Meta: | |||||
| model = Account | |||||
| exclude = () # | |||||
| @@ -0,0 +1,28 @@ | |||||
| # Generated by Django 4.1.9 on 2023-07-17 23:26 | |||||
| from django.db import migrations, models | |||||
| class Migration(migrations.Migration): | |||||
| initial = True | |||||
| dependencies = [ | |||||
| ] | |||||
| operations = [ | |||||
| migrations.CreateModel( | |||||
| name='Account', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('name', models.CharField(max_length=100)), | |||||
| ('address', models.CharField(max_length=200)), | |||||
| ('phone_number', models.CharField(max_length=20)), | |||||
| ('email', models.EmailField(max_length=254)), | |||||
| ('created_at', models.DateTimeField(auto_now_add=True)), | |||||
| ('total_revenue', models.DecimalField(decimal_places=2, default=0, max_digits=10)), | |||||
| ('total_expenses', models.DecimalField(decimal_places=2, default=0, max_digits=10)), | |||||
| ('total_investments', models.DecimalField(decimal_places=2, default=0, max_digits=10)), | |||||
| ], | |||||
| ), | |||||
| ] | |||||
| @@ -0,0 +1,72 @@ | |||||
| # Generated by Django 4.1.9 on 2023-07-18 11:13 | |||||
| from django.db import migrations, models | |||||
| import django.db.models.deletion | |||||
| class Migration(migrations.Migration): | |||||
| dependencies = [ | |||||
| ('common', '0001_initial'), | |||||
| ('employee', '0002_alter_employee_user'), | |||||
| ('accounts', '0001_initial'), | |||||
| ] | |||||
| operations = [ | |||||
| migrations.CreateModel( | |||||
| name='Client', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('name', models.CharField(max_length=100)), | |||||
| ], | |||||
| ), | |||||
| migrations.CreateModel( | |||||
| name='Expense', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('category', models.CharField(choices=[('Food', 'Food'), ('Fuel', 'Fuel'), ('Traveling', 'Traveling'), ('Gifts', 'Gifts')], max_length=100)), | |||||
| ('title', models.CharField(max_length=100)), | |||||
| ('bill_number', models.CharField(max_length=100)), | |||||
| ('date', models.DateField()), | |||||
| ('reimbursement', models.BooleanField()), | |||||
| ('bank_account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.bankdetails')), | |||||
| ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='employee.employee')), | |||||
| ], | |||||
| ), | |||||
| migrations.CreateModel( | |||||
| name='Income', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('type', models.CharField(choices=[('Invoice', 'Invoice'), ('Dividend', 'Dividend')], max_length=10)), | |||||
| ('title', models.CharField(max_length=100)), | |||||
| ('invoice_number', models.CharField(max_length=100)), | |||||
| ('date', models.DateField()), | |||||
| ('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.client')), | |||||
| ], | |||||
| ), | |||||
| migrations.CreateModel( | |||||
| name='Project', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('name', models.CharField(max_length=100)), | |||||
| ], | |||||
| ), | |||||
| migrations.CreateModel( | |||||
| name='Reimbursement', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('title', models.CharField(max_length=100)), | |||||
| ('rate', models.DecimalField(decimal_places=2, max_digits=10)), | |||||
| ('quantity', models.PositiveIntegerField()), | |||||
| ('status', models.CharField(max_length=10)), | |||||
| ], | |||||
| ), | |||||
| migrations.DeleteModel( | |||||
| name='Account', | |||||
| ), | |||||
| migrations.AddField( | |||||
| model_name='income', | |||||
| name='project', | |||||
| field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.project'), | |||||
| ), | |||||
| ] | |||||
| @@ -0,0 +1,76 @@ | |||||
| from django.db import models | |||||
| # Create your models here. | |||||
| from employee.models import Employee | |||||
| from common.models import BankDetails | |||||
| class Client(models.Model): | |||||
| name = models.CharField(max_length=100) | |||||
| # Other fields for client information | |||||
| def __str__(self): | |||||
| return self.name | |||||
| class Project(models.Model): | |||||
| name = models.CharField(max_length=100) | |||||
| # Other fields for project information | |||||
| def __str__(self): | |||||
| return self.name | |||||
| class Income(models.Model): | |||||
| TYPE_CHOICES = [ | |||||
| ('Invoice', 'Invoice'), | |||||
| ('Dividend', 'Dividend'), | |||||
| ] | |||||
| type = models.CharField(max_length=10, choices=TYPE_CHOICES) | |||||
| title = models.CharField(max_length=100) | |||||
| invoice_number = models.CharField(max_length=100) | |||||
| date = models.DateField() | |||||
| client = models.ForeignKey(Client, on_delete=models.CASCADE) | |||||
| project = models.ForeignKey(Project, on_delete=models.CASCADE) | |||||
| # Other fields specific to income | |||||
| def __str__(self): | |||||
| return self.title | |||||
| class Expense(models.Model): | |||||
| CATEGORY_CHOICES = [ | |||||
| ('Food', 'Food'), | |||||
| ('Fuel', 'Fuel'), | |||||
| ('Traveling', 'Traveling'), | |||||
| ('Gifts', 'Gifts'), | |||||
| # Other expense categories | |||||
| ] | |||||
| category = models.CharField(max_length=100, choices=CATEGORY_CHOICES) | |||||
| title = models.CharField(max_length=100) | |||||
| bill_number = models.CharField(max_length=100) | |||||
| date = models.DateField() | |||||
| employee = models.ForeignKey(Employee, on_delete=models.CASCADE) | |||||
| bank_account = models.ForeignKey(BankDetails, on_delete=models.CASCADE) | |||||
| reimbursement = models.BooleanField() | |||||
| # Other fields specific to expenses | |||||
| def __str__(self): | |||||
| return self.title | |||||
| class Reimbursement(models.Model): | |||||
| STATUS_CHOICES=[ | |||||
| ('Paid','Paid'), | |||||
| ('Due', 'Due'), | |||||
| ('Overdue', 'Overdue'), | |||||
| ] | |||||
| title = models.CharField(max_length=100) | |||||
| rate = models.DecimalField(max_digits=10, decimal_places=2) | |||||
| quantity = models.PositiveIntegerField() | |||||
| status = models.CharField(max_length=10, choices=STATUS_CHOICES) # Paid, Due, Overdue | |||||
| # Other fields specific to reimbursements | |||||
| def __str__(self): | |||||
| return self.title | |||||
| @@ -0,0 +1,19 @@ | |||||
| from rest_framework import serializers | |||||
| from .models import Income, Expense, Reimbursement | |||||
| class IncomeSerializer(serializers.ModelSerializer): | |||||
| class Meta: | |||||
| model = Income | |||||
| fields = '__all__' | |||||
| class ExpenseSerializer(serializers.ModelSerializer): | |||||
| class Meta: | |||||
| model = Expense | |||||
| fields = '__all__' | |||||
| class ReimbursementSerializer(serializers.ModelSerializer): | |||||
| class Meta: | |||||
| model = Reimbursement | |||||
| fields = '__all__' | |||||
| @@ -0,0 +1,17 @@ | |||||
| from rest_framework import viewsets | |||||
| from .models import Income, Expense, Reimbursement | |||||
| from .serializers import IncomeSerializer, ExpenseSerializer, ReimbursementSerializer | |||||
| class IncomeViewSet(viewsets.ModelViewSet): | |||||
| queryset = Income.objects.all() | |||||
| serializer_class = IncomeSerializer | |||||
| class ExpenseViewSet(viewsets.ModelViewSet): | |||||
| queryset = Expense.objects.all() | |||||
| serializer_class = ExpenseSerializer | |||||
| class ReimbursementViewSet(viewsets.ModelViewSet): | |||||
| queryset = Reimbursement.objects.all() | |||||
| serializer_class = ReimbursementSerializer | |||||
| @@ -1,8 +0,0 @@ | |||||
| from django.shortcuts import render | |||||
| from django.contrib import messages | |||||
| from django.shortcuts import redirect | |||||
| def signup_redirect(request): | |||||
| messages.error(request, "Something wrong here, it may be that you already have account!") | |||||
| return redirect("homepage") | |||||
| @@ -0,0 +1,48 @@ | |||||
| # Generated by Django 4.1.9 on 2023-07-17 22:36 | |||||
| from django.db import migrations, models | |||||
| class Migration(migrations.Migration): | |||||
| initial = True | |||||
| dependencies = [ | |||||
| ] | |||||
| operations = [ | |||||
| migrations.CreateModel( | |||||
| name='Address', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('address_line_1', models.CharField(max_length=200)), | |||||
| ('address_line_2', models.CharField(blank=True, max_length=200)), | |||||
| ('city', models.CharField(max_length=50)), | |||||
| ('state', models.CharField(max_length=50)), | |||||
| ('zip_code', models.CharField(max_length=10)), | |||||
| ('country', models.CharField(max_length=50)), | |||||
| ], | |||||
| options={ | |||||
| 'db_table': 'address', | |||||
| }, | |||||
| ), | |||||
| migrations.CreateModel( | |||||
| name='BankDetails', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('beneficiary_name', models.CharField(max_length=50)), | |||||
| ('bank_name', models.CharField(max_length=50)), | |||||
| ('account_number', models.CharField(max_length=20)), | |||||
| ('ifsc_code', models.CharField(max_length=20)), | |||||
| ('branch_name', models.CharField(max_length=50)), | |||||
| ('upi_id', models.CharField(blank=True, max_length=50)), | |||||
| ], | |||||
| ), | |||||
| migrations.CreateModel( | |||||
| name='NatureOfBusiness', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('name', models.CharField(max_length=50)), | |||||
| ], | |||||
| ), | |||||
| ] | |||||
| @@ -0,0 +1,47 @@ | |||||
| # Generated by Django 4.1.9 on 2023-07-19 21:26 | |||||
| from django.db import migrations, models | |||||
| import django.db.models.deletion | |||||
| class Migration(migrations.Migration): | |||||
| initial = True | |||||
| dependencies = [ | |||||
| ('common', '0001_initial'), | |||||
| ] | |||||
| operations = [ | |||||
| migrations.CreateModel( | |||||
| name='Company', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('legal_name', models.CharField(max_length=256)), | |||||
| ('trade_name', models.CharField(max_length=256)), | |||||
| ('cin', models.CharField(max_length=64)), | |||||
| ('cin_proof', models.FileField(null=True, upload_to='company_proofs/')), | |||||
| ('gstin', models.CharField(max_length=16)), | |||||
| ('gstin_proof', models.FileField(null=True, upload_to='company_proofs/')), | |||||
| ('date_of_incorporation', models.DateField()), | |||||
| ('date_of_incorporation_proof', models.FileField(null=True, upload_to='company_proofs/')), | |||||
| ('pan', models.CharField(max_length=16)), | |||||
| ('pan_proof', models.FileField(null=True, upload_to='company_proofs/')), | |||||
| ('iec', models.CharField(max_length=16)), | |||||
| ('iec_proof', models.FileField(null=True, upload_to='company_proofs/')), | |||||
| ('msme_code', models.CharField(max_length=64)), | |||||
| ('msme_proof', models.FileField(null=True, upload_to='company_proofs/')), | |||||
| ('provident_fund_code_number', models.CharField(max_length=32)), | |||||
| ('provident_fund_code_number_proof', models.FileField(null=True, upload_to='company_proofs/')), | |||||
| ('se_registration_number', models.CharField(max_length=32)), | |||||
| ('se_registration_number_proof', models.FileField(null=True, upload_to='company_proofs/')), | |||||
| ('phone_number', models.CharField(max_length=13)), | |||||
| ('support_email', models.EmailField(max_length=254, null=True, unique=True)), | |||||
| ('address', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.address')), | |||||
| ('nature_of_business', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.natureofbusiness')), | |||||
| ], | |||||
| options={ | |||||
| 'db_table': 'company', | |||||
| }, | |||||
| ), | |||||
| ] | |||||
| @@ -1,5 +1,5 @@ | |||||
| from django.shortcuts import render | from django.shortcuts import render | ||||
| from rest_framework import viewsets | |||||
| from rest_framework import viewsets, permissions | |||||
| from .models import Company | from .models import Company | ||||
| from .form import CompanyForm | from .form import CompanyForm | ||||
| from .serializers import CompanySerializer | from .serializers import CompanySerializer | ||||
| @@ -7,6 +7,7 @@ from .serializers import CompanySerializer | |||||
| class CompanyViewSet(viewsets.ModelViewSet): | class CompanyViewSet(viewsets.ModelViewSet): | ||||
| queryset = Company.objects.all() | queryset = Company.objects.all() | ||||
| serializer_class = CompanySerializer | serializer_class = CompanySerializer | ||||
| permission_classes = [permissions.IsAuthenticated] | |||||
| def perform_create(self, serializer): | def perform_create(self, serializer): | ||||
| form_data = self.request.data.get('form') | form_data = self.request.data.get('form') | ||||
| @@ -1,7 +1,7 @@ | |||||
| from django.contrib import admin | from django.contrib import admin | ||||
| # Register your models here. | # Register your models here. | ||||
| from employee.models import Department, Employee | |||||
| from employee.models import Employee | |||||
| admin.site.register(Department) | |||||
| admin.site.register(Employee) | admin.site.register(Employee) | ||||
| @@ -0,0 +1,42 @@ | |||||
| # Generated by Django 4.1.9 on 2023-07-17 22:35 | |||||
| from django.conf import settings | |||||
| from django.db import migrations, models | |||||
| import django.db.models.deletion | |||||
| class Migration(migrations.Migration): | |||||
| initial = True | |||||
| dependencies = [ | |||||
| migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |||||
| ('common', '__first__'), | |||||
| ] | |||||
| operations = [ | |||||
| migrations.CreateModel( | |||||
| name='Role', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('name', models.CharField(max_length=50, unique=True)), | |||||
| ], | |||||
| ), | |||||
| migrations.CreateModel( | |||||
| name='Employee', | |||||
| fields=[ | |||||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
| ('first_name', models.CharField(max_length=30)), | |||||
| ('last_name', models.CharField(max_length=30)), | |||||
| ('personal_email', models.EmailField(max_length=254, unique=True)), | |||||
| ('official_email', models.EmailField(max_length=254, unique=True)), | |||||
| ('phone_number', models.CharField(max_length=13)), | |||||
| ('job_title', models.CharField(max_length=100)), | |||||
| ('ctc', models.DecimalField(decimal_places=2, max_digits=10)), | |||||
| ('address', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.address')), | |||||
| ('bank_details', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='common.bankdetails')), | |||||
| ('role', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='employee.role')), | |||||
| ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | |||||
| ], | |||||
| ), | |||||
| ] | |||||
| @@ -0,0 +1,21 @@ | |||||
| # Generated by Django 4.1.9 on 2023-07-17 22:46 | |||||
| from django.conf import settings | |||||
| from django.db import migrations, models | |||||
| import django.db.models.deletion | |||||
| class Migration(migrations.Migration): | |||||
| dependencies = [ | |||||
| migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |||||
| ('employee', '0001_initial'), | |||||
| ] | |||||
| operations = [ | |||||
| migrations.AlterField( | |||||
| model_name='employee', | |||||
| name='user', | |||||
| field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='employee', to=settings.AUTH_USER_MODEL), | |||||
| ), | |||||
| ] | |||||
| @@ -1,15 +1,11 @@ | |||||
| from django.db import models | from django.db import models | ||||
| from common.models import BankDetails, Address | from common.models import BankDetails, Address | ||||
| class Department(models.Model): | |||||
| name = models.CharField(max_length=50) | |||||
| def __str__(self): | |||||
| return self.name | |||||
| from django.contrib.auth.models import User | |||||
| class Employee(models.Model): | class Employee(models.Model): | ||||
| user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee') | |||||
| # Rest of the fields... | |||||
| role = models.ForeignKey('Role', on_delete=models.SET_NULL, null=True) | |||||
| first_name = models.CharField(max_length=30) | first_name = models.CharField(max_length=30) | ||||
| last_name = models.CharField(max_length=30) | last_name = models.CharField(max_length=30) | ||||
| personal_email = models.EmailField(unique=True) | personal_email = models.EmailField(unique=True) | ||||
| @@ -17,9 +13,14 @@ class Employee(models.Model): | |||||
| phone_number = models.CharField(max_length=13) | phone_number = models.CharField(max_length=13) | ||||
| address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True) | address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True) | ||||
| job_title = models.CharField(max_length=100) | job_title = models.CharField(max_length=100) | ||||
| department = models.ManyToManyField(Department) | |||||
| ctc = models.DecimalField(max_digits=10, decimal_places=2) | ctc = models.DecimalField(max_digits=10, decimal_places=2) | ||||
| bank_details = models.OneToOneField(BankDetails, on_delete=models.CASCADE) | bank_details = models.OneToOneField(BankDetails, on_delete=models.CASCADE) | ||||
| def __str__(self): | def __str__(self): | ||||
| return f"{self.first_name} {self.last_name}" | return f"{self.first_name} {self.last_name}" | ||||
| class Role(models.Model): | |||||
| name = models.CharField(max_length=50, unique=True) | |||||
| def __str__(self): | |||||
| return self.name | |||||
| @@ -0,0 +1,45 @@ | |||||
| from rest_framework import permissions | |||||
| def has_permission(self, request, view): | |||||
| if request.user.is_authenticated: | |||||
| try: | |||||
| employee = request.user.employee | |||||
| return employee is not None and employee.role is not None | |||||
| except Employee.DoesNotExist: | |||||
| return False | |||||
| return False | |||||
| from .models import Employee | |||||
| class EmployeeAPIPermission(permissions.BasePermission): | |||||
| def has_permission(self, request, view): | |||||
| if request.method in permissions.SAFE_METHODS: | |||||
| return True # Allow GET requests for all users | |||||
| user = request.user | |||||
| if user.is_authenticated and user.role: | |||||
| role_name = user.role.name | |||||
| if role_name == 'Admin': | |||||
| return True # Allow CRUD operations for Admin role | |||||
| elif role_name == 'Employee' and request.method in ['GET', 'PUT']: | |||||
| return True # Allow GET and PUT requests for Employee role | |||||
| return False | |||||
| from rest_framework import permissions | |||||
| class GoogleAuthenticatedPermission(permissions.BasePermission): | |||||
| def has_permission(self, request, view): | |||||
| # Check if the user is authenticated | |||||
| if not request.user.is_authenticated: | |||||
| return False | |||||
| # Check if the user is authenticated with a Google account | |||||
| if 'email' not in request.session: | |||||
| return False | |||||
| # Perform additional checks if needed | |||||
| # For example, verify the email in request.session with the email from id_token_data | |||||
| return True | |||||
| @@ -1,12 +1,29 @@ | |||||
| from rest_framework import serializers | from rest_framework import serializers | ||||
| from common.serializers import BankDetailsSerializer, AddressSerializer | from common.serializers import BankDetailsSerializer, AddressSerializer | ||||
| from .models import Employee | |||||
| from .models import Employee,Role | |||||
| from common.models import BankDetails, Address | |||||
| class EmployeeSerializer(serializers.ModelSerializer): | class EmployeeSerializer(serializers.ModelSerializer): | ||||
| address = AddressSerializer() | |||||
| bank_details = BankDetailsSerializer() | bank_details = BankDetailsSerializer() | ||||
| address = AddressSerializer() | |||||
| class Meta: | class Meta: | ||||
| model = Employee | model = Employee | ||||
| fields = '__all__' | |||||
| fields = '__all__' | |||||
| def create(self, validated_data): | |||||
| bank_details_data = validated_data.pop('bank_details') | |||||
| address_data = validated_data.pop('address') | |||||
| bank_details = BankDetails.objects.create(**bank_details_data) | |||||
| address = Address.objects.create(**address_data) | |||||
| employee = Employee.objects.create(bank_details=bank_details, address=address, **validated_data) | |||||
| return employee | |||||
| class RoleSerializer(serializers.ModelSerializer): | |||||
| class Meta: | |||||
| model = Role | |||||
| fields = '__all__' | |||||
| @@ -1,25 +1,27 @@ | |||||
| from rest_framework import viewsets | |||||
| from rest_framework import viewsets,permissions | |||||
| from .models import Employee | from .models import Employee | ||||
| from .serializers import EmployeeSerializer | from .serializers import EmployeeSerializer | ||||
| from .forms import EmployeeForm | from .forms import EmployeeForm | ||||
| from rest_framework import generics, permissions | |||||
| from .models import Role | |||||
| from .serializers import RoleSerializer | |||||
| from .permissions import EmployeeAPIPermission,GoogleAuthenticatedPermission | |||||
| class EmployeeViewSet(viewsets.ModelViewSet): | |||||
| class RoleListCreateAPIView(generics.ListCreateAPIView): | |||||
| queryset = Role.objects.all() | |||||
| serializer_class = RoleSerializer | |||||
| permission_classes = [permissions.IsAuthenticated, permissions.IsAdminUser] | |||||
| class EmployeeListCreateAPIView(generics.ListCreateAPIView): | |||||
| queryset = Employee.objects.all() | |||||
| serializer_class = EmployeeSerializer | |||||
| permission_classes = [permissions.IsAuthenticated| EmployeeAPIPermission] | |||||
| class EmployeeRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView): | |||||
| queryset = Employee.objects.all() | queryset = Employee.objects.all() | ||||
| serializer_class = EmployeeSerializer | serializer_class = EmployeeSerializer | ||||
| permission_classes = [permissions.IsAuthenticated | EmployeeAPIPermission] | |||||
| def perform_create(self, serializer): | |||||
| form_data = self.request.data.get('form') | |||||
| form = EmployeeForm(form_data) | |||||
| if form.is_valid(): | |||||
| employee = serializer.save() | |||||
| form.instance = employee | |||||
| form.save() | |||||
| def perform_update(self, serializer): | |||||
| form_data = self.request.data.get('form') | |||||
| form = EmployeeForm(form_data, instance=serializer.instance) | |||||
| if form.is_valid(): | |||||
| employee = serializer.save() | |||||
| form.instance = employee | |||||
| form.save() | |||||
| @@ -0,0 +1,3 @@ | |||||
| from django.contrib import admin | |||||
| # Register your models here. | |||||
| @@ -0,0 +1,6 @@ | |||||
| from django.apps import AppConfig | |||||
| class GoogleAuthConfig(AppConfig): | |||||
| default_auto_field = 'django.db.models.BigAutoField' | |||||
| name = 'google_auth' | |||||
| @@ -1,3 +1,3 @@ | |||||
| from django.db import models | from django.db import models | ||||
| # Create your models here. | |||||
| # Create your models here. | |||||
| @@ -0,0 +1,3 @@ | |||||
| from django.test import TestCase | |||||
| # Create your tests here. | |||||
| @@ -0,0 +1,9 @@ | |||||
| from django.urls import path | |||||
| from . import views | |||||
| app_name = 'google_auth' | |||||
| urlpatterns = [ | |||||
| path('login/', views.login, name='login'), | |||||
| path('callback/', views.callback, name='callback'), | |||||
| ] | |||||
| @@ -0,0 +1,34 @@ | |||||
| from django.shortcuts import redirect | |||||
| from google.oauth2 import id_token | |||||
| from django.conf import settings | |||||
| from django.urls import reverse_lazy | |||||
| import requests | |||||
| from google.auth.transport import requests as google_requests | |||||
| def login(request): | |||||
| # Redirect the user to the Google authentication URL | |||||
| redirect_uri = request.build_absolute_uri(reverse_lazy('google_auth:callback')) | |||||
| authorization_url = f'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={settings.GOOGLE_OAUTH2_CLIENT_ID}&redirect_uri={redirect_uri}&scope=openid%20email%20profile' | |||||
| return redirect(authorization_url) | |||||
| def callback(request): | |||||
| authorization_code = request.GET.get('code') | |||||
| token_url = 'https://oauth2.googleapis.com/token' | |||||
| redirect_uri = request.build_absolute_uri(reverse_lazy('google_auth:callback')) | |||||
| token_request_data = { | |||||
| 'code': authorization_code, | |||||
| 'client_id': settings.GOOGLE_OAUTH2_CLIENT_ID, | |||||
| 'client_secret': settings.GOOGLE_OAUTH2_CLIENT_SECRET, | |||||
| 'redirect_uri': redirect_uri, | |||||
| 'grant_type': 'authorization_code' | |||||
| } | |||||
| token_response = requests.post(token_url, data=token_request_data) | |||||
| token_response_data = token_response.json() | |||||
| id_token_data = id_token.verify_oauth2_token( | |||||
| token_response_data['id_token'], | |||||
| google_requests.Request(), | |||||
| settings.GOOGLE_OAUTH2_CLIENT_ID | |||||
| ) | |||||
| return redirect('http://127.0.0.1:8000') | |||||
| @@ -0,0 +1,12 @@ | |||||
| <!DOCTYPE html> | |||||
| <html> | |||||
| <head> | |||||
| <title>Home</title> | |||||
| <script> | |||||
| window.location.href = "http://127.0.0.1:8000/api/"; // Replace "https://example.com" with your desired redirect URL | |||||
| </script> | |||||
| </head> | |||||
| <body> | |||||
| <h1>Redirecting...</h1> | |||||
| </body> | |||||
| </html> | |||||
| @@ -1,3 +0,0 @@ | |||||
| from django.shortcuts import render | |||||
| # Create your views here. | |||||
| @@ -27,27 +27,26 @@ DEBUG = True | |||||
| ALLOWED_HOSTS = ['*'] | ALLOWED_HOSTS = ['*'] | ||||
| GOOGLE_OAUTH2_CLIENT_ID = "611194092059-kk4bhv18i19cvngmi3335gtvk4nmp25d.apps.googleusercontent.com" | |||||
| GOOGLE_OAUTH2_CLIENT_SECRET ="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" | |||||
| # Application definition | # Application definition | ||||
| INSTALLED_APPS = [ | INSTALLED_APPS = [ | ||||
| 'django.contrib.admin', | 'django.contrib.admin', | ||||
| 'django.contrib.auth', | 'django.contrib.auth', | ||||
| 'django.contrib.contenttypes', | 'django.contrib.contenttypes', | ||||
| 'django.contrib.sessions', | 'django.contrib.sessions', | ||||
| 'django.contrib.messages', | |||||
| 'django.contrib.staticfiles', | 'django.contrib.staticfiles', | ||||
| 'company', | 'company', | ||||
| 'common', | 'common', | ||||
| 'accounts', | |||||
| 'employee', | 'employee', | ||||
| 'client', | 'client', | ||||
| 'rest_framework', | 'rest_framework', | ||||
| 'django.contrib.sites', | |||||
| 'allauth', | |||||
| 'allauth.account', | |||||
| 'allauth.socialaccount', | |||||
| 'allauth.socialaccount.providers.google', | |||||
| ] | |||||
| "django.contrib.messages", | |||||
| "google_auth", | |||||
| ] | |||||
| MIDDLEWARE = [ | MIDDLEWARE = [ | ||||
| 'django.middleware.security.SecurityMiddleware', | 'django.middleware.security.SecurityMiddleware', | ||||
| @@ -79,58 +78,50 @@ TEMPLATES = [ | |||||
| WSGI_APPLICATION = 'workx.wsgi.application' | WSGI_APPLICATION = 'workx.wsgi.application' | ||||
| # AUTH_PASSWORD_VALIDATORS = [ | |||||
| # { | |||||
| # "NAME": "django.contrib.auth.password_validation." | |||||
| # "UserAttributeSimilarityValidator", | |||||
| # }, | |||||
| # { | |||||
| # "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", | |||||
| # }, | |||||
| # { | |||||
| # "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", | |||||
| # }, | |||||
| # { | |||||
| # "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", | |||||
| # }, | |||||
| # ] | |||||
| # Database | # Database | ||||
| # https://docs.djangoproject.com/en/4.1/ref/settings/#databases | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases | ||||
| DATABASES = { | DATABASES = { | ||||
| 'default': { | 'default': { | ||||
| 'ENGINE': 'djongo', | |||||
| 'NAME': 'WorkX', | |||||
| 'ENFORCE_SCHEMA': True, # Optional: enforce the database schema | |||||
| 'ENGINE': 'django.db.backends.postgresql_psycopg2', | |||||
| 'NAME': 'workxx', | |||||
| 'USER': 'postgres', | |||||
| 'PASSWORD': '123456', | |||||
| 'HOST': 'localhost', | |||||
| 'PORT': '5432', | |||||
| } | } | ||||
| } | } | ||||
| SITE_ID = 2 | |||||
| SOCIALACCOUNT_LOGIN_ON_GET=True | |||||
| AUTHENTICATION_BACKENDS = [ | |||||
| 'allauth.account.auth_backends.AuthenticationBackend' | |||||
| ] | |||||
| SOCIALACCOUNT_PROVIDERS = { | |||||
| 'google': { | |||||
| 'SCOPE': [ | |||||
| 'profile', | |||||
| 'email', | |||||
| ], | |||||
| 'AUTH_PARAMS': { | |||||
| 'access_type': 'online', | |||||
| } | |||||
| } | |||||
| } | |||||
| LOGIN_REDIRECT_URL = '/api/employee/' | |||||
| # Password validation | # Password validation | ||||
| # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators | ||||
| AUTH_PASSWORD_VALIDATORS = [ | |||||
| { | |||||
| 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', | |||||
| }, | |||||
| { | |||||
| 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', | |||||
| }, | |||||
| { | |||||
| 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', | |||||
| }, | |||||
| { | |||||
| 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', | |||||
| }, | |||||
| ] | |||||
| # GOOGLE_SSO_SCOPES = [ # default values | |||||
| # "openid", | |||||
| # "https://www.googleapis.com/auth/userinfo.email", | |||||
| # "https://www.googleapis.com/auth/userinfo.profile", | |||||
| # ] | |||||
| # Internationalization | # Internationalization | ||||
| @@ -15,20 +15,25 @@ Including another URLconf | |||||
| """ | """ | ||||
| from django.contrib import admin | from django.contrib import admin | ||||
| from django.urls import path,include | from django.urls import path,include | ||||
| from social_django.urls import urlpatterns as social_django_urls | |||||
| from employee.views import EmployeeViewSet | |||||
| from accounts.views import IncomeViewSet,ExpenseViewSet,ReimbursementViewSet | |||||
| from employee.views import EmployeeListCreateAPIView,EmployeeRetrieveUpdateAPIView,RoleListCreateAPIView | |||||
| from company.views import CompanyViewSet | from company.views import CompanyViewSet | ||||
| from rest_framework import routers | from rest_framework import routers | ||||
| from authUser.view import signup_redirect | |||||
| from google_auth.views import login, callback | |||||
| router = routers.DefaultRouter() | router = routers.DefaultRouter() | ||||
| router.register(r'employee', EmployeeViewSet) | |||||
| router.register(r'company', CompanyViewSet) | router.register(r'company', CompanyViewSet) | ||||
| router.register(r'accounts/income', IncomeViewSet) | |||||
| router.register(r'accounts/reimbursement', ReimbursementViewSet) | |||||
| router.register(r'accounts/expense', ExpenseViewSet) | |||||
| urlpatterns = [ | urlpatterns = [ | ||||
| path('admin/', admin.site.urls), | path('admin/', admin.site.urls), | ||||
| path('api/', include(router.urls)), | |||||
| path("", include("allauth.urls")), | |||||
| path('social/signup/', signup_redirect, name='signup_redirect'), | |||||
| ] | |||||
| path('', include(router.urls)), | |||||
| path('employees/', EmployeeListCreateAPIView.as_view(), name='employee-list-create'), | |||||
| path('employees/<int:pk>/', EmployeeRetrieveUpdateAPIView.as_view(), name='employee-retrieve-update'), | |||||
| path('roles/', RoleListCreateAPIView.as_view(), name='role-list-create'), | |||||
| path('google-auth/', include('google_auth.urls')), | |||||
| ] | |||||