Skip to content

Commit ed042ae

Browse files
committed
First Commit
1 parent bf38b2e commit ed042ae

File tree

137 files changed

+2682
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+2682
-0
lines changed

Procfile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
release: python manage.py migrate
2+
web: gunicorn crm.wsgi --preload --log-file -

agent/__init__.py

Whitespace-only changes.
129 Bytes
Binary file not shown.
126 Bytes
Binary file not shown.
170 Bytes
Binary file not shown.
167 Bytes
Binary file not shown.

agent/__pycache__/apps.cpython-38.pyc

404 Bytes
Binary file not shown.

agent/__pycache__/apps.cpython-39.pyc

401 Bytes
Binary file not shown.
624 Bytes
Binary file not shown.
621 Bytes
Binary file not shown.
1.2 KB
Binary file not shown.
1.21 KB
Binary file not shown.
167 Bytes
Binary file not shown.
164 Bytes
Binary file not shown.

agent/__pycache__/urls.cpython-38.pyc

1.04 KB
Binary file not shown.

agent/__pycache__/urls.cpython-39.pyc

1.04 KB
Binary file not shown.
6.71 KB
Binary file not shown.
6.74 KB
Binary file not shown.

agent/admin.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.

agent/apps.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class AgentConfig(AppConfig):
5+
default_auto_field = 'django.db.models.BigAutoField'
6+
name = 'agent'

agent/forms.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from django import forms
2+
from lead.models import User
3+
from lead.models import Agent
4+
5+
class AgentCreateForm(forms.ModelForm):
6+
class Meta:
7+
model = User
8+
fields = ('username', 'email', 'first_name','last_name')

agent/migrations/__init__.py

Whitespace-only changes.
Binary file not shown.
Binary file not shown.

agent/mixin.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
from django.contrib.auth.mixins import AccessMixin
3+
from django.shortcuts import redirect
4+
5+
class OrganiserLoginRequiredMixin(AccessMixin):
6+
"""Verify that the current user is authenticated and is an organiser"""
7+
def dispatch(self, request, *args, **kwargs):
8+
if not request.user.is_authenticated or not request.user.is_organiser:
9+
return redirect('lead:lead-list')
10+
return super().dispatch(request, *args, **kwargs)
11+
12+
class AgentLoginRequiredMixin(AccessMixin):
13+
"""Verify that the current user is authenticated and is an agent"""
14+
def dispatch(self, request, *args, **kwargs):
15+
if not request.user.is_authenticated or not request.user.is_agent:
16+
return redirect('lead:lead-login')
17+
return super().dispatch(request, *args, **kwargs)

agent/models.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.db import models
2+
3+
# Create your models here.

agent/tests.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.test import TestCase
2+
3+
# Create your tests here.

agent/urls.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from django.contrib.auth.views import LogoutView
2+
from django.urls import path
3+
from . import views
4+
5+
app_name = 'agent'
6+
urlpatterns = [
7+
path('agent/login/', views.AgentLoginView.as_view(), name='agent-login'),
8+
path('agent/logout/', LogoutView.as_view(next_page='home'), name='agent-logout'),
9+
path('agent/change-password/', views.AgentUpdatePassword.as_view(), name='password_change_done'),
10+
path('agent/profile/<str:username>/', views.AgentProfileView.as_view(), name='agent_profile'),
11+
path('agent/profile/<str:username>/update/', views.AgentUpdateProfileView.as_view(), name='update-profile'),
12+
path('agent/', views.AgentListView.as_view(), name='agent-list'),
13+
path('agent/create/', views.AgentCreateView.as_view(), name='agent-create'),
14+
path('agent/<int:pk>/detail/', views.AgentDetailView.as_view(), name='agent-detail'),
15+
path('agent/<int:pk>/update/', views.AgentUpdateView.as_view(), name='agent-update'),
16+
path('agent/<int:pk>/delete/', views.AgentDeleteView.as_view(), name='agent-delete'),
17+
]

agent/views.py

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
from django.contrib.auth.forms import PasswordChangeForm
2+
from django.core.mail import send_mail
3+
from django.http.response import HttpResponseRedirect
4+
from django.views.generic.base import TemplateView
5+
from agent.mixin import AgentLoginRequiredMixin, OrganiserLoginRequiredMixin
6+
from agent.forms import AgentCreateForm
7+
from lead.forms import LeadProfileForm, LeadUserProfileForm
8+
from django.contrib.auth.decorators import login_required
9+
from django.contrib.auth.views import LoginView, PasswordChangeView
10+
from django.urls.base import reverse, reverse_lazy
11+
from django.views.generic.detail import DetailView
12+
from django.views.generic.list import ListView
13+
from lead.models import Agent, Profile
14+
from django.contrib import messages
15+
import random
16+
from django.shortcuts import get_object_or_404, redirect, render
17+
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
18+
19+
class AgentLoginView(LoginView):
20+
template_name = 'agent/login.html'
21+
fields = '__all__'
22+
redirect_authenticated_user = False
23+
24+
def get_success_url(self):
25+
return reverse_lazy('lead:lead-list')
26+
27+
class AgentProfileView(DetailView):
28+
model = Profile
29+
template_name = 'agent/agent_profile.html'
30+
31+
def get_object(self):
32+
object = get_object_or_404(Profile, user__username=self.kwargs['username'])
33+
return object
34+
35+
#Update Password for Agent
36+
class AgentUpdatePassword(AgentLoginRequiredMixin, PasswordChangeView):
37+
form_class = PasswordChangeForm
38+
template_name = 'agent/password_change_form.html'
39+
40+
def get_success_url(self):
41+
return reverse_lazy('agent:agent_profile', kwargs={'username':self.request.user.username})
42+
43+
def form_valid(self, form):
44+
messages.success(self.request, f'Password updated successfully.')
45+
return super(AgentUpdatePassword, self).form_valid(form)
46+
47+
#Agent Profile Update
48+
class AgentUpdateProfileView(AgentLoginRequiredMixin, TemplateView):
49+
template_name = 'agent/agent_profile_update.html'
50+
51+
def get_success_url(self):
52+
return reverse_lazy('agent:agent_profile', kwargs={'username':self.request.user.username})
53+
54+
def get_context_data(self, **kwargs):
55+
context = super().get_context_data(**kwargs)
56+
context['form_profile'] = LeadProfileForm(instance=self.request.user.profile,)
57+
context['form_user'] = LeadUserProfileForm(instance=self.request.user)
58+
return context
59+
60+
def post(self, request, *args, **kwargs):
61+
form_profile = LeadProfileForm(instance=self.request.user.profile, data=request.POST, files=request.FILES)
62+
form_user = LeadUserProfileForm(instance=self.request.user, data=request.POST)
63+
if form_profile.is_valid() and form_user.is_valid():
64+
form_profile.save()
65+
form_user.save()
66+
messages.success(request, f'Account has been updated Successfully.')
67+
return HttpResponseRedirect(self.get_success_url())
68+
69+
class AgentListView(OrganiserLoginRequiredMixin, ListView):
70+
template_name = 'agent/agent_list.html'
71+
context_object_name = 'agents'
72+
73+
def get_queryset(self):
74+
queryset = Agent.objects.filter(organisation=self.request.user.profile)
75+
return queryset
76+
77+
class AgentCreateView(OrganiserLoginRequiredMixin, CreateView):
78+
form_class = AgentCreateForm
79+
template_name = 'agent/agent_create.html'
80+
success_url = reverse_lazy('agent:agent-list')
81+
82+
def form_valid(self, form):
83+
password = random.randint(1,10000)
84+
user = form.save(commit=False)
85+
user.is_agent = True
86+
user.is_organiser = False
87+
user.set_password(f'{password}')
88+
user.save()
89+
Agent.objects.create(
90+
user = user,
91+
organisation = self.request.user.profile,
92+
)
93+
subject = 'You are invited as an agent'
94+
msg = f'Login details:\n{user.username}\n{password}\nAnd then reset the password.'
95+
send_mail(
96+
subject=subject,
97+
message=msg,
98+
from_email='test@admin.com',
99+
recipient_list=[{f'{user.email}'}])
100+
messages.success(self.request, f'Agent create successfully!\nCheck {user.email} for login details.')
101+
return super(AgentCreateView, self).form_valid(form)
102+
103+
class AgentDetailView(OrganiserLoginRequiredMixin, DetailView):
104+
template_name = 'agent/agent_detail.html'
105+
context_object_name = 'agent'
106+
107+
def get_object(self):
108+
object = get_object_or_404(Agent, id=self.kwargs['pk'])
109+
return object
110+
111+
class AgentUpdateView(OrganiserLoginRequiredMixin, UpdateView):
112+
fields = ('user',)
113+
context_object_name = 'agent'
114+
template_name = 'agent/agent_update.html'
115+
116+
def form_valid(self, form):
117+
messages.success(self.request, f'agent updated successfully!')
118+
return super(AgentUpdateView, self).form_valid(form)
119+
120+
def get_object(self):
121+
object = get_object_or_404(Agent, id=self.kwargs['pk'])
122+
return object
123+
124+
def get_success_url(self):
125+
return reverse('agent:agent-detail', kwargs={'pk':self.get_object().id})
126+
127+
class AgentDeleteView(OrganiserLoginRequiredMixin, DeleteView):
128+
template_name = 'agent/agent_delete.html'
129+
context_object_name = 'agent'
130+
success_url = reverse_lazy('agent:agent-list')
131+
132+
def get_object(self):
133+
object = get_object_or_404(Agent, id=self.kwargs['pk'])
134+
return object
135+
136+
def form_valid(self, form):
137+
messages.success(self.request, f'agent deleted successfully!')
138+
return super(AgentUpdateView, self).form_valid(form)

category/__init__.py

Whitespace-only changes.
132 Bytes
Binary file not shown.
129 Bytes
Binary file not shown.
173 Bytes
Binary file not shown.
170 Bytes
Binary file not shown.
413 Bytes
Binary file not shown.
410 Bytes
Binary file not shown.
170 Bytes
Binary file not shown.
167 Bytes
Binary file not shown.
659 Bytes
Binary file not shown.
656 Bytes
Binary file not shown.
2.39 KB
Binary file not shown.
2.4 KB
Binary file not shown.

category/admin.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.

category/apps.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class CategoryConfig(AppConfig):
5+
default_auto_field = 'django.db.models.BigAutoField'
6+
name = 'category'

category/migrations/__init__.py

Whitespace-only changes.
Binary file not shown.
Binary file not shown.

category/models.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.db import models
2+
3+
# Create your models here.

category/tests.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.test import TestCase
2+
3+
# Create your tests here.

category/urls.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from django.contrib.auth.views import LogoutView
2+
from django.urls import path
3+
from . import views
4+
5+
app_name = 'category'
6+
urlpatterns = [
7+
path('category/', views.CategoryListView.as_view(), name='category-list'),
8+
path('category/unassigned-lead/', views.CategoryUnassignedListView.as_view(), name='unassigned-lead'),
9+
path('category/converted-lead/', views.CategoryConvertedListView.as_view(), name='converted-lead'),
10+
path('category/contacted-lead/', views.CategoryContactedListView.as_view(), name='contacted-lead'),
11+
]

category/views.py

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from lead.models import Lead
2+
from agent.mixin import OrganiserLoginRequiredMixin
3+
from django.shortcuts import render
4+
from django.views.generic.list import ListView
5+
from django.views.generic.detail import DetailView
6+
7+
class CategoryListView(OrganiserLoginRequiredMixin, ListView):
8+
model = Lead
9+
template_name = 'category/category_list.html'
10+
11+
def get_context_data(self, **kwargs):
12+
context = super().get_context_data(**kwargs)
13+
loginUser = self.request.user
14+
context.update({
15+
'UnassignedLeadCount': Lead.objects.filter(
16+
organisation=loginUser.profile,
17+
category__name='Unassigned').count(),
18+
'ContactedLeadCount': Lead.objects.filter(
19+
organisation=loginUser.profile,
20+
category__name='Contacted').count(),
21+
'ConvertedLeadCount': Lead.objects.filter(
22+
organisation=loginUser.profile,
23+
category__name='Converted').count(),
24+
})
25+
return context
26+
27+
28+
class CategoryContactedListView(OrganiserLoginRequiredMixin, ListView):
29+
model = Lead
30+
template_name = 'category/contact_lead.html'
31+
32+
def get_context_data(self, **kwargs):
33+
context = super().get_context_data(**kwargs)
34+
loginUser = self.request.user
35+
context.update({
36+
'ContactedLeads': Lead.objects.filter(
37+
organisation=loginUser.profile,
38+
category__name='Contacted'),
39+
})
40+
return context
41+
42+
class CategoryUnassignedListView(OrganiserLoginRequiredMixin, ListView):
43+
model = Lead
44+
template_name = 'category/unassigned_lead.html'
45+
46+
def get_context_data(self, **kwargs):
47+
context = super().get_context_data(**kwargs)
48+
loginUser = self.request.user
49+
context.update({
50+
'UnassignedLeads': Lead.objects.filter(
51+
organisation=loginUser.profile,
52+
category__name='Unassigned'),
53+
})
54+
return context
55+
56+
class CategoryConvertedListView(OrganiserLoginRequiredMixin, ListView):
57+
model = Lead
58+
template_name = 'category/converted_lead.html'
59+
60+
def get_context_data(self, **kwargs):
61+
context = super().get_context_data(**kwargs)
62+
loginUser = self.request.user
63+
context.update({
64+
'ConvertedLeads': Lead.objects.filter(
65+
organisation=loginUser.profile,
66+
category__name='Converted'),
67+
})
68+
return context
69+
70+

crm/.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*.pyc
2+
*~
3+
__pycache__
4+
myvenv
5+
db.sqlite3
6+
/static
7+
.DS_Store
8+
.env

crm/__init__.py

Whitespace-only changes.

crm/asgi.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
ASGI config for crm project.
3+
4+
It exposes the ASGI callable as a module-level variable named ``application``.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
8+
"""
9+
10+
import os
11+
12+
from django.core.asgi import get_asgi_application
13+
14+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'crm.settings')
15+
16+
application = get_asgi_application()

0 commit comments

Comments
 (0)