diff --git a/README.md b/README.md index e0153cd..c086f78 100644 --- a/README.md +++ b/README.md @@ -66,14 +66,6 @@ python manage.py runserver Then open http://localhost:8000 in your borwser and create a new account with test as company name. We mapped `test.localhost` to `127.0.0.1`. So, it should work properly. -### To edit content - -``` -python manage.py create_blog_user 'username' - -``` - -The above command will add the user as blog admin to edit content at /blog/admin/ ### Useful tools and packages ``` diff --git a/accounts/models.py b/accounts/models.py index ab02598..0e52c12 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -18,14 +18,15 @@ class Tags(models.Model): def save(self, *args, **kwargs): self.slug = slugify(self.name) - super(Tags, self).save(*args, **kwargs) + super().save(*args, **kwargs) class Account(models.Model): ACCOUNT_STATUS_CHOICE = (("open", "Open"), ("close", "Close")) - name = models.CharField(pgettext_lazy("Name of Account", "Name"), max_length=64) + name = models.CharField(pgettext_lazy( + "Name of Account", "Name"), max_length=64) email = models.EmailField() phone = PhoneNumberField(null=True) industry = models.CharField( @@ -38,9 +39,12 @@ class Account(models.Model): billing_address_line = models.CharField( _("Address"), max_length=255, blank=True, null=True ) - billing_street = models.CharField(_("Street"), max_length=55, blank=True, null=True) - billing_city = models.CharField(_("City"), max_length=255, blank=True, null=True) - billing_state = models.CharField(_("State"), max_length=255, blank=True, null=True) + billing_street = models.CharField( + _("Street"), max_length=55, blank=True, null=True) + billing_city = models.CharField( + _("City"), max_length=255, blank=True, null=True) + billing_state = models.CharField( + _("State"), max_length=255, blank=True, null=True) billing_postcode = models.CharField( _("Post/Zip-code"), max_length=64, blank=True, null=True ) @@ -67,7 +71,8 @@ class Account(models.Model): contacts = models.ManyToManyField( "contacts.Contact", related_name="account_contacts" ) - assigned_to = models.ManyToManyField(Profile, related_name="account_assigned_users") + assigned_to = models.ManyToManyField( + Profile, related_name="account_assigned_users") teams = models.ManyToManyField(Teams, related_name="account_teams") org = models.ForeignKey( Org, on_delete=models.SET_NULL, null=True, blank=True, related_name="account_org" diff --git a/accounts/serializer.py b/accounts/serializer.py index a7fa74c..928429a 100644 --- a/accounts/serializer.py +++ b/accounts/serializer.py @@ -56,8 +56,7 @@ class Meta: class EmailSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): - request_obj = kwargs.pop("request_obj", None) - super(EmailSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class Meta: model = Email @@ -95,14 +94,14 @@ class EmailLogSerializer(serializers.ModelSerializer): class Meta: model = Email - fields = "email" "contact" "is_sent" + fields = ["email", "contact", "is_sent"] class AccountCreateSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): account_view = kwargs.pop("account", False) request_obj = kwargs.pop("request_obj", None) - super(AccountCreateSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["status"].required = False if account_view: self.fields["billing_address_line"].required = True diff --git a/accounts/tasks.py b/accounts/tasks.py index ead525d..547132d 100644 --- a/accounts/tasks.py +++ b/accounts/tasks.py @@ -4,12 +4,11 @@ from celery import Celery from django.conf import settings from django.core.mail import EmailMessage -from django.shortcuts import reverse from django.template import Context, Template from django.template.loader import render_to_string from accounts.models import Account, Email, EmailLog -from common.models import User, Profile +from common.models import Profile from common.utils import convert_to_custom_timezone app = Celery("redis://") @@ -59,7 +58,7 @@ def send_email(email_obj_id): @app.task def send_email_to_assigned_user( - recipients, from_email, domain="demo.django-crm.io", protocol="http" + recipients, from_email ): """ Send Mail To Users When they are assigned to a contact """ account = Account.objects.filter(id=from_email).first() @@ -71,7 +70,7 @@ def send_email_to_assigned_user( if profile: recipients_list.append(profile.user.email) context = {} - context["url"] = protocol + "://" + domain + context["url"] = settings.DOMAIN_NAME context["user"] = profile.user context["account"] = account context["created_by"] = created_by diff --git a/accounts/views.py b/accounts/views.py index 3f736ae..6b77ef3 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,21 +1,12 @@ -import pytz -from django.conf import settings -from django.contrib.sites.shortcuts import get_current_site from django.db.models import Q - -from accounts.models import Account, Tags, Email +from accounts.models import Account, Tags from accounts.tasks import send_email_to_assigned_user, send_email from accounts import swagger_params from accounts.serializer import ( AccountSerializer, - TagsSerailizer, AccountCreateSerializer, ) from common.models import Profile, Attachments, Comment -from common.utils import ( - COUNTRIES, - INDCHOICES, -) from common.custom_auth import JSONWebTokenAuthentication from common.serializer import ProfileSerializer, CommentSerializer, AttachmentsSerializer from common.utils import ( @@ -28,13 +19,9 @@ ) from django.shortcuts import get_object_or_404 from contacts.models import Contact -from leads.models import Lead from opportunity.models import SOURCES, STAGES, Opportunity -from cases.models import Case from cases.serializer import CaseSerializer from contacts.serializer import ContactSerializer -from leads.serializer import LeadSerializer -from teams.serializer import TeamsSerializer from tasks.serializer import TaskSerializer from opportunity.serializer import OpportunitySerializer from invoices.serializer import InvoiceSerailizer @@ -62,7 +49,8 @@ def get_context_data(self, **kwargs): if len(self.request.data) == 0 else self.request.data ) - queryset = self.model.objects.filter(org=self.request.org) + queryset = self.model.objects.filter( + org=self.request.org).order_by('-id') if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: queryset = queryset.filter( Q(created_by=self.request.profile) | Q( @@ -70,83 +58,61 @@ def get_context_data(self, **kwargs): ).distinct() if params: - request_post = params - if request_post: - if request_post.get("name"): - queryset = queryset.filter( - name__icontains=request_post.get("name")) - if request_post.get("city"): - queryset = queryset.filter( - billing_city__contains=request_post.get("city") - ) - if request_post.get("industry"): - queryset = queryset.filter( - industry__icontains=request_post.get("industry") - ) - if request_post.get("tags"): - queryset = queryset.filter( - tags__in=json.loads(request_post.get("tags")) - ).distinct() - context = {} - search = False - if ( - params.get("name") - or params.get("city") - or params.get("industry") - or params.get("tag") - ): - search = True - context["search"] = search + if params.get("name"): + queryset = queryset.filter( + name__icontains=params.get("name")) + if params.get("city"): + queryset = queryset.filter( + billing_city__contains=params.get("city") + ) + if params.get("industry"): + queryset = queryset.filter( + industry__icontains=params.get("industry") + ) + if params.get("tags"): + queryset = queryset.filter( + tags__in=json.loads(params.get("tags")) + ).distinct() - queryset_open = queryset.filter(status="open").order_by("id") + context = {} + queryset_open = queryset.filter(status="open") results_accounts_open = self.paginate_queryset( queryset_open.distinct(), self.request, view=self ) + if results_accounts_open: + offset = queryset_open.filter( + id__gte=results_accounts_open[-1].id).count() + if offset == queryset_open.count(): + offset = None + else: + offset = 0 accounts_open = AccountSerializer( results_accounts_open, many=True).data context["per_page"] = 10 context["active_accounts"] = { - "accounts_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, + "offset": offset, "open_accounts": accounts_open, } - queryset_close = queryset.filter(status="close").order_by("id") + queryset_close = queryset.filter(status="close") results_accounts_close = self.paginate_queryset( queryset_close.distinct(), self.request, view=self ) + if results_accounts_close: + offset = queryset_close.filter( + id__gte=results_accounts_close[-1].id).count() + if offset == queryset_close.count(): + offset = None + else: + offset = 0 accounts_close = AccountSerializer( results_accounts_close, many=True).data context["closed_accounts"] = { - "accounts_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, + "offset": offset, "close_accounts": accounts_close, } - - context["users"] = ProfileSerializer( - Profile.objects.filter(is_active=True, - org=self.request.org).order_by("user__email"), - many=True, - ).data context["industries"] = INDCHOICES - tag_ids = Account.objects.filter( - org=self.request.org).values_list("tags", flat=True).distinct() - context["tags"] = TagsSerailizer( - Tags.objects.filter(id__in=tag_ids), many=True - ).data - if params.get("tag", None): - context["request_tags"] = self.params.get("tag") - else: - context["request_tags"] = None - - TIMEZONE_CHOICES = [(tz, tz) for tz in pytz.common_timezones] - context["timezones"] = TIMEZONE_CHOICES - context["settings_timezone"] = settings.TIME_ZONE return context @swagger_auto_schema( @@ -162,7 +128,6 @@ def get(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): params = request.query_params if len( request.data) == 0 else request.data - data = {} serializer = AccountCreateSerializer( data=params, request_obj=request, account=True ) @@ -171,18 +136,11 @@ def post(self, request, *args, **kwargs): account_object = serializer.save( created_by=request.profile, org=request.org) if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter(id=contact) - if obj_contact.exists(): - account_object.contacts.add(contact) - else: - account_object.delete() - data["contacts"] = "Please enter valid contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + contacts_list = json.loads(params.get("contacts")) + contacts = Contact.objects.filter( + id__in=contacts_list, org=request.org) + if contacts: + account_object.contacts.add(*contacts) if params.get("tags"): tags = json.loads(params.get("tags")) for tag in tags: @@ -192,38 +150,20 @@ def post(self, request, *args, **kwargs): else: tag_obj = Tags.objects.create(name=tag) account_object.tags.add(tag_obj) - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter( - id=team, org=request.org - ) - if teams_ids.exists(): - account_object.teams.add(team) - else: - account_object.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org + ) + if teams: + account_object.teams.add(*teams) if params.get("assigned_to"): - assinged_to_users_ids = json.loads( + assigned_to_list = json.loads( params.get("assigned_to")) - - for user_id in assinged_to_users_ids: - user = Profile.objects.filter( - id=user_id, org=request.org) - if user.exists(): - account_object.assigned_to.add(user_id) - else: - account_object.delete() - data["assigned_to"] = "Please enter valid user" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + profiles = Profile.objects.filter( + id__in=assigned_to_list, org=request.org, is_active=True) + if profiles: + account_object.assigned_to.add(*profiles) if self.request.FILES.get("account_attachment"): attachment = Attachments() @@ -234,17 +174,12 @@ def post(self, request, *args, **kwargs): attachment.attachment = request.FILES.get("account_attachment") attachment.save() - assigned_to_list = list( + recipients = list( account_object.assigned_to.all().values_list("id", flat=True) ) - - recipients = assigned_to_list - current_site = get_current_site(self.request) send_email_to_assigned_user.delay( recipients, account_object.id, - domain=current_site.domain, - protocol=self.request.scheme, ) return Response( {"error": False, "message": "Account Created Successfully"}, @@ -270,11 +205,10 @@ def put(self, request, pk, format=None): params = request.query_params if len( request.data) == 0 else request.data account_object = self.get_object(pk=pk) - data = {} if account_object.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, - status=status.HTTP_404_NOT_FOUND, + status=status.HTTP_403_FORBIDDEN, ) serializer = AccountCreateSerializer( account_object, data=params, request_obj=request, account=True @@ -297,21 +231,15 @@ def put(self, request, pk, format=None): previous_assigned_to_users = list( account_object.assigned_to.all().values_list("id", flat=True) ) + account_object.contacts.clear() if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter( - id=contact, org=request.org - ) - if obj_contact.exists(): - account_object.contacts.add(contact) - else: - data["contacts"] = "Please enter valid Contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + contacts_list = json.loads(params.get("contacts")) + contacts = Contact.objects.filter( + id__in=contacts_list, org=request.org) + if contacts: + account_object.contacts.add(*contacts) + account_object.tags.clear() if params.get("tags"): tags = json.loads(params.get("tags")) @@ -323,38 +251,23 @@ def put(self, request, pk, format=None): tag_obj = Tags.objects.create(name=tag) account_object.tags.add(tag_obj) - if self.request.profile.role == "ADMIN": - account_object.teams.clear() - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter( - id=team, org=request.org - ) - if teams_ids.exists(): - account_object.teams.add(team) - else: - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - account_object.assigned_to.clear() - if params.get("assigned_to"): - assinged_to_users_ids = json.loads( - params.get("assigned_to")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter( - id=user_id, org=request.org) - if user.exists(): - account_object.assigned_to.add(user_id) - else: - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + account_object.teams.clear() + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org + ) + if teams: + account_object.teams.add(*teams) + + account_object.assigned_to.clear() + if params.get("assigned_to"): + assigned_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assigned_to_list, org=request.org, is_active=True) + if profiles: + account_object.assigned_to.add(*profiles) if self.request.FILES.get("account_attachment"): attachment = Attachments() @@ -371,12 +284,9 @@ def put(self, request, pk, format=None): ) recipients = list(set(assigned_to_list) - set(previous_assigned_to_users)) - current_site = get_current_site(self.request) send_email_to_assigned_user.delay( recipients, account_object.id, - domain=current_site.domain, - protocol=self.request.scheme, ) return Response( {"error": False, "message": "Account Updated Successfully"}, @@ -436,15 +346,13 @@ def get(self, request, pk, format=None): status=status.HTTP_403_FORBIDDEN, ) - comment_permission = ( - True - if ( - self.request.profile == self.account.created_by - or self.request.profile.is_admin - or self.request.profile.role == "ADMIN" - ) - else False - ) + comment_permission = False + if ( + self.request.profile == self.account.created_by + or self.request.profile.is_admin + or self.request.profile.role == "ADMIN" + ): + comment_permission = True if self.request.profile.is_admin or self.request.profile.role == "ADMIN": users_mention = list(Profile.objects.filter( @@ -516,7 +424,7 @@ def post(self, request, pk, **kwargs): if self.account_obj.org != request.org: return Response( {"error": True, "errors": "User company does not match with header...."}, - status=status.HTTP_400_BAD_REQUEST + status=status.HTTP_403_FORBIDDEN ) if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: if not ( @@ -596,14 +504,13 @@ def put(self, request, pk, format=None): {"error": True, "errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to edit this Comment", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to edit this Comment", + }, + status=status.HTTP_403_FORBIDDEN, + ) @swagger_auto_schema(tags=["Accounts"], manual_parameters=swagger_params.organization_params) def delete(self, request, pk, format=None): @@ -618,14 +525,13 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Comment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) class AccountAttachmentView(APIView): @@ -646,14 +552,13 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Attachment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to delete this Attachment", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to delete this Attachment", + }, + status=status.HTTP_403_FORBIDDEN, + ) class AccountCreateMailView(APIView): @@ -707,8 +612,7 @@ def post(self, request, pk, *args, **kwargs): {"error": False, "message": "Email sent successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - {"error": True, "errors": serializer.errors}, - status=status.HTTP_400_BAD_REQUEST, - ) + return Response( + {"error": True, "errors": serializer.errors}, + status=status.HTTP_400_BAD_REQUEST, + ) diff --git a/cases/serializer.py b/cases/serializer.py index 3c4726e..bfc4971 100644 --- a/cases/serializer.py +++ b/cases/serializer.py @@ -40,9 +40,8 @@ class CaseCreateSerializer(serializers.ModelSerializer): closed_on = serializers.DateField def __init__(self, *args, **kwargs): - case_view = kwargs.pop("case", False) request_obj = kwargs.pop("request_obj", None) - super(CaseCreateSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.org = request_obj.org def validate_name(self, name): diff --git a/cases/tasks.py b/cases/tasks.py index 789df1d..ea896c7 100644 --- a/cases/tasks.py +++ b/cases/tasks.py @@ -1,8 +1,6 @@ from celery import Celery from django.conf import settings -from django.core.mail import EmailMultiAlternatives, EmailMessage -from django.db.models import Q -from django.shortcuts import reverse +from django.core.mail import EmailMessage from django.template.loader import render_to_string from accounts.models import Profile @@ -13,7 +11,7 @@ @app.task def send_email_to_assigned_user( - recipients, case_id, domain="demo.django-crm.io", protocol="http" + recipients, case_id ): """ Send Mail To Users When they are assigned to a case """ case = Case.objects.get(id=case_id) @@ -24,7 +22,7 @@ def send_email_to_assigned_user( if profile: recipients_list.append(profile.user.email) context = {} - context["url"] = protocol + "://" + domain + context["url"] = settings.DOMAIN_NAME context["user"] = profile.user context["case"] = case context["created_by"] = created_by diff --git a/cases/views.py b/cases/views.py index f98448f..588de5e 100644 --- a/cases/views.py +++ b/cases/views.py @@ -1,6 +1,3 @@ -import pytz -from django.conf import settings -from django.contrib.sites.shortcuts import get_current_site from django.db.models import Q from cases.models import Case @@ -12,10 +9,9 @@ ) from accounts.models import Account from accounts.serializer import AccountSerializer -from common.models import User, Attachments, Comment, Profile +from common.models import Attachments, Comment, Profile from common.custom_auth import JSONWebTokenAuthentication from common.serializer import ( - ProfileSerializer, CommentSerializer, AttachmentsSerializer, ) @@ -26,7 +22,6 @@ ) from contacts.models import Contact from contacts.serializer import ContactSerializer -from teams.serializer import TeamsSerializer from teams.models import Teams from rest_framework import status @@ -50,9 +45,10 @@ def get_context_data(self, **kwargs): if len(self.request.data) == 0 else self.request.data ) - queryset = self.model.objects.filter(org=self.request.org) - accounts = Account.objects.filter(org=self.request.org) - contacts = Contact.objects.filter(org=self.request.org) + queryset = self.model.objects.filter( + org=self.request.org).order_by('-id') + accounts = Account.objects.filter(org=self.request.org).order_by('-id') + contacts = Contact.objects.filter(org=self.request.org).order_by('-id') profiles = Profile.objects.filter( is_active=True, org=self.request.org) if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: @@ -81,42 +77,29 @@ def get_context_data(self, **kwargs): queryset = queryset.filter(account=params.get("account")) context = {} - search = False - if ( - params.get("name") - or params.get("status") - or params.get("priority") - or params.get("account") - ): - search = True - context["search"] = search results_cases = self.paginate_queryset( queryset, self.request, view=self) cases = CaseSerializer(results_cases, many=True).data - context["per_page"] = 10 + if results_cases: + offset = queryset.filter(id__gte=results_cases[-1].id).count() + if offset == queryset.count(): + offset = None + else: + offset = 0 context.update( { "cases_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, + "offset": offset, } ) - if search: - context["cases"] = cases - return context context["cases"] = cases - context["users"] = ProfileSerializer(profiles, many=True).data context["status"] = STATUS_CHOICE context["priority"] = PRIORITY_CHOICE context["type_of_case"] = CASE_TYPE context["accounts_list"] = AccountSerializer(accounts, many=True).data context["contacts_list"] = ContactSerializer(contacts, many=True).data - if self.request.profile == "ADMIN": - context["teams_list"] = TeamsSerializer( - Teams.objects.filter(org=self.request.org), many=True).data return context @swagger_auto_schema( @@ -132,7 +115,6 @@ def get(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): params = request.query_params if len( request.data) == 0 else request.data - data = {} serializer = CaseCreateSerializer(data=params, request_obj=request) if serializer.is_valid(): cases_obj = serializer.save( @@ -143,48 +125,26 @@ def post(self, request, *args, **kwargs): ) if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter(id=contact, org=request.org) - if obj_contact.exists(): - cases_obj.contacts.add(contact) - else: - cases_obj.delete() - data["contacts"] = "Please enter valid contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - obj_team = Teams.objects.filter(id=team, org=request.org) - if obj_team.exists(): - cases_obj.teams.add(team) - else: - cases_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if params.get("assigned_to"): - assinged_to_users_ids = json.loads( - params.get("assigned_to")) - - for user_id in assinged_to_users_ids: - user = Profile.objects.filter(id=user_id, org=request.org) - if user.exists(): - cases_obj.assigned_to.add(user_id) - else: - cases_obj.delete() - data["assigned_to"] = "Please enter valid user" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + contacts_list = json.loads(params.get("contacts")) + contacts = Contact.objects.filter( + id__in=contacts_list, org=request.org) + if contacts: + cases_obj.contacts.add(*contacts) + + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + if teams.exists(): + cases_obj.teams.add(*teams) + + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org, is_active=True) + if profiles: + cases_obj.assigned_to.add(*profiles) if self.request.FILES.get("case_attachment"): attachment = Attachments() @@ -196,16 +156,12 @@ def post(self, request, *args, **kwargs): "case_attachment") attachment.save() - assigned_to_list = list( + recipients = list( cases_obj.assigned_to.all().values_list("id", flat=True) ) - current_site = get_current_site(request) - recipients = assigned_to_list send_email_to_assigned_user.delay( recipients, cases_obj.id, - domain=current_site.domain, - protocol=self.request.scheme, ) return Response( {"error": False, "message": "Case Created Successfully"}, @@ -233,11 +189,10 @@ def put(self, request, pk, format=None): params = request.query_params if len( request.data) == 0 else request.data cases_object = self.get_object(pk=pk) - data = {} if cases_object.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, - status=status.HTTP_404_NOT_FOUND, + status=status.HTTP_403_FORBIDDEN, ) if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: if not ( @@ -256,7 +211,6 @@ def put(self, request, pk, format=None): cases_object, data=params, request_obj=request, - case=True, ) if serializer.is_valid(): @@ -268,47 +222,28 @@ def put(self, request, pk, format=None): ) cases_object.contacts.clear() if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter(id=contact, org=request.org) - if obj_contact.exists(): - cases_object.contacts.add(contact) - else: - data["contacts"] = "Please enter valid Contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - if self.request.profile.role == "ADMIN": - cases_object.teams.clear() - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - obj_team = Teams.objects.filter(id=team, org=request.org) - if obj_team.exists(): - cases_object.teams.add(team) - else: - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - cases_object.assigned_to.clear() - if params.get("assigned_to"): - assinged_to_users_ids = json.loads( - params.get("assigned_to")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter(id=user_id, org=request.org) - if user.exists(): - cases_object.assigned_to.add(user_id) - else: - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + contacts_list = json.loads(params.get("contacts")) + contacts = Contact.objects.filter( + id__in=contacts_list, org=request.org) + if contacts: + cases_object.contacts.add(*contacts) + + cases_object.teams.clear() + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + if teams.exists(): + cases_object.teams.add(*teams) + + cases_object.assigned_to.clear() + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org, is_active=True) + if profiles: + cases_object.assigned_to.add(*profiles) if self.request.FILES.get("case_attachment"): attachment = Attachments() @@ -325,12 +260,9 @@ def put(self, request, pk, format=None): ) recipients = list(set(assigned_to_list) - set(previous_assigned_to_users)) - current_site = get_current_site(self.request) send_email_to_assigned_user.delay( recipients, cases_object.id, - domain=current_site.domain, - protocol=self.request.scheme, ) return Response( {"error": False, "message": "Case Updated Successfully"}, @@ -349,7 +281,7 @@ def delete(self, request, pk, format=None): if self.object.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, - status=status.HTTP_404_NOT_FOUND + status=status.HTTP_403_FORBIDDEN ) if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: if self.request.profile != self.object.created_by: @@ -374,7 +306,7 @@ def get(self, request, pk, format=None): if self.cases.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, - status=status.HTTP_404_NOT_FOUND, + status=status.HTTP_403_FORBIDDEN, ) context = {} context["cases_obj"] = CaseSerializer(self.cases).data @@ -391,15 +323,14 @@ def get(self, request, pk, format=None): status=status.HTTP_403_FORBIDDEN, ) - comment_permission = ( - True - if ( - self.request.profile == self.cases.created_by - or self.request.profile.is_admin - or self.request.profile.role == "ADMIN" - ) - else False - ) + comment_permission = False + + if ( + self.request.profile == self.cases.created_by + or self.request.profile.is_admin + or self.request.profile.role == "ADMIN" + ): + comment_permission = True if self.request.profile.is_admin or self.request.profile.role == "ADMIN": users_mention = list( @@ -409,7 +340,8 @@ def get(self, request, pk, format=None): ) elif self.request.profile != self.cases.created_by: if self.cases.created_by: - users_mention = [{"username": self.cases.created_by.user.username}] + users_mention = [ + {"username": self.cases.created_by.user.username}] else: users_mention = [] else: @@ -426,13 +358,6 @@ def get(self, request, pk, format=None): "contacts": ContactSerializer( self.cases.contacts.all(), many=True ).data, - "users": ProfileSerializer( - Profile.objects.filter( - is_active=True, - org=self.request.org - ).order_by("user__email"), - many=True, - ).data, "status": STATUS_CHOICE, "priority": PRIORITY_CHOICE, "type_of_case": CASE_TYPE, @@ -451,13 +376,13 @@ def post(self, request, pk, **kwargs): if len(self.request.data) == 0 else self.request.data ) + self.cases_obj = Case.objects.get(pk=pk) if self.cases_obj.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, - status=status.HTTP_404_NOT_FOUND - ) + status=status.HTTP_403_FORBIDDEN + ) context = {} - self.cases_obj = Case.objects.get(pk=pk) comment_serializer = CommentSerializer(data=params) if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: if not ( @@ -533,14 +458,13 @@ def put(self, request, pk, format=None): {"error": True, "errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to perform this action.", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to perform this action.", + }, + status=status.HTTP_403_FORBIDDEN, + ) @swagger_auto_schema( tags=["Cases"], manual_parameters=swagger_params.organization_params @@ -557,14 +481,13 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Comment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You do not have permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You do not have permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) class CaseAttachmentView(APIView): @@ -587,11 +510,10 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Attachment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to perform this action.", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to perform this action.", + }, + status=status.HTTP_403_FORBIDDEN, + ) diff --git a/common/access_decorators_mixins.py b/common/access_decorators_mixins.py index 076133c..e401c44 100644 --- a/common/access_decorators_mixins.py +++ b/common/access_decorators_mixins.py @@ -1,8 +1,5 @@ -from functools import wraps - -from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin +from django.contrib.auth.mixins import AccessMixin from django.core.exceptions import PermissionDenied -from django.shortcuts import redirect def sales_access_required(function): @@ -15,8 +12,7 @@ def wrap(request, *args, **kwargs): or request.user.has_sales_access ): return function(request, *args, **kwargs) - else: - raise PermissionDenied + raise PermissionDenied return wrap @@ -31,8 +27,7 @@ def wrap(request, *args, **kwargs): or request.user.has_marketing_access ): return function(request, *args, **kwargs) - else: - raise PermissionDenied + raise PermissionDenied return wrap @@ -49,11 +44,10 @@ def dispatch(self, request, *args, **kwargs): or request.user.is_superuser or request.user.has_sales_access ): - return super(SalesAccessRequiredMixin, self).dispatch( + return super().dispatch( request, *args, **kwargs ) - else: - return self.handle_no_permission() + return self.handle_no_permission() class MarketingAccessRequiredMixin(AccessMixin): @@ -68,11 +62,10 @@ def dispatch(self, request, *args, **kwargs): or request.user.is_superuser or request.user.has_marketing_access ): - return super(MarketingAccessRequiredMixin, self).dispatch( + return super().dispatch( request, *args, **kwargs ) - else: - return self.handle_no_permission() + return self.handle_no_permission() def admin_login_required(function): @@ -81,7 +74,6 @@ def admin_login_required(function): def wrap(request, *args, **kwargs): if request.user.role == "ADMIN" or request.user.is_superuser: return function(request, *args, **kwargs) - else: - raise PermissionDenied + raise PermissionDenied return wrap diff --git a/common/custom_auth.py b/common/custom_auth.py index 689a4f2..5c6429e 100644 --- a/common/custom_auth.py +++ b/common/custom_auth.py @@ -1,14 +1,9 @@ import jwt -import base64 - -# from .models import User -# from django.contrib.auth import get_user_model from django.utils.encoding import smart_text from django.utils.translation import ugettext as _ from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication from rest_framework.authentication import get_authorization_header -from django.conf import settings from rest_framework_jwt.settings import api_settings try: diff --git a/common/models.py b/common/models.py index 8aa76da..df9a11d 100644 --- a/common/models.py +++ b/common/models.py @@ -3,7 +3,6 @@ import datetime import os import time -from django.core.cache import cache from django.db import models from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager @@ -20,7 +19,6 @@ ) from common.utils import COUNTRIES, ROLES from django.utils import timezone -from django.conf import settings def img_url(self, filename): @@ -135,7 +133,8 @@ def __str__(self): class Profile(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) - org = models.ForeignKey(Org, null=True, on_delete=models.CASCADE, blank=True) + org = models.ForeignKey( + Org, null=True, on_delete=models.CASCADE, blank=True) phone = PhoneNumberField(null=True, unique=True) alternate_phone = PhoneNumberField(null=True) address = models.ForeignKey( @@ -160,7 +159,7 @@ class Meta: def save(self, *args, **kwargs): """ by default the expiration time is set to 2 hours """ self.key_expires = timezone.now() + datetime.timedelta(hours=2) - super(Profile, self).save(*args, **kwargs) + super().save(*args, **kwargs) @property def is_admin(self): @@ -387,7 +386,8 @@ class Document(models.Model): status = models.CharField( choices=DOCUMENT_STATUS_CHOICE, max_length=64, default="active" ) - shared_to = models.ManyToManyField(Profile, related_name="document_shared_to") + shared_to = models.ManyToManyField( + Profile, related_name="document_shared_to") teams = models.ManyToManyField( "teams.Teams", related_name="document_teams") org = models.ForeignKey( @@ -478,7 +478,7 @@ def __str__(self): def save(self, *args, **kwargs): if not self.apikey or self.apikey is None or self.apikey == "": self.apikey = generate_key() - super(APISettings, self).save(*args, **kwargs) + super().save(*args, **kwargs) class Google(models.Model): diff --git a/common/serializer.py b/common/serializer.py index 7084003..81783b3 100644 --- a/common/serializer.py +++ b/common/serializer.py @@ -99,7 +99,7 @@ class Meta: def __init__(self, *args, **kwargs): account_view = kwargs.pop("account", False) - super(BillingAddressSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if account_view: self.fields["address_line"].required = True @@ -128,13 +128,12 @@ class Meta: def __init__(self, *args, **kwargs): self.org = kwargs.pop("org", None) - super(CreateUserSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["first_name"].required = True self.fields["password"].required = False self.fields["profile_pic"].required = False self.fields["skype_ID"].required = False - def validate_email(self, email): if self.instance: if self.instance.email != email: @@ -143,10 +142,9 @@ def validate_email(self, email): return email raise serializers.ValidationError("Email already exists") return email - else: - if not Profile.objects.filter(user__email=email.lower(), org=self.org).exists(): - return email - raise serializers.ValidationError('Given Email id already exists') + if not Profile.objects.filter(user__email=email.lower(), org=self.org).exists(): + return email + raise serializers.ValidationError('Given Email id already exists') class CreateProfileSerializer(serializers.ModelSerializer): @@ -163,7 +161,7 @@ class Meta: ) def __init__(self, *args, **kwargs): - super(CreateProfileSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["alternate_phone"].required = False self.fields["role"].required = True self.fields["phone"].required = True @@ -289,7 +287,7 @@ class Meta: class DocumentCreateSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): request_obj = kwargs.pop("request_obj", None) - super(DocumentCreateSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["title"].required = True self.org = request_obj.org @@ -304,11 +302,10 @@ def validate_title(self, title): raise serializers.ValidationError( "Document with this Title already exists" ) - else: - if Document.objects.filter(title__iexact=title, org=self.org).exists(): - raise serializers.ValidationError( - "Document with this Title already exists" - ) + if Document.objects.filter(title__iexact=title, org=self.org).exists(): + raise serializers.ValidationError( + "Document with this Title already exists" + ) return title class Meta: @@ -337,7 +334,7 @@ def find_urls(string): class APISettingsSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): - super(APISettingsSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class Meta: model = APISettings @@ -384,7 +381,7 @@ class PasswordChangeSerializer(serializers.Serializer): retype_password = serializers.CharField(max_length=100) def __init__(self, *args, **kwargs): - super(PasswordChangeSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def validate_old_password(self, pwd): if not check_password(pwd, self.context.get('user').password): diff --git a/common/tasks.py b/common/tasks.py index d618a9a..253e5fb 100644 --- a/common/tasks.py +++ b/common/tasks.py @@ -17,17 +17,17 @@ @app.task def send_email_to_new_user( - profile_id, org_id, domain="demo.django-crm.io", protocol="http" + profile_id, org_id ): """ Send Mail To Users When their account is created """ - profile_obj = Profile.objects.filter(id=profile_id).last() + profile_obj = Profile.objects.filter(id=profile_id, org_id=org_id).last() user_obj = profile_obj.user if profile_obj: context = {} user_email = user_obj.email - context["url"] = protocol + "://" + domain + context["url"] = settings.DOMAIN_NAME context["uid"] = (urlsafe_base64_encode(force_bytes(user_obj.pk)),) context["token"] = account_activation_token.make_token(user_obj) time_delta_two_hours = datetime.datetime.strftime( @@ -55,7 +55,7 @@ def send_email_to_new_user( @app.task def send_email_user_mentions( - comment_id, called_from, domain="demo.django-crm.io", protocol="http" + comment_id, called_from, ): """ Send Mail To Mentioned Users In The Comment """ comment = Comment.objects.filter(id=comment_id).first() @@ -81,30 +81,25 @@ def send_email_user_mentions( context = {} context["commented_by"] = comment.commented_by context["comment_description"] = comment.comment + subject = None if called_from == "accounts": - context["url"] = protocol + "://" + domain subject = "New comment on Account. " elif called_from == "contacts": - context["url"] = protocol + "://" + domain subject = "New comment on Contact. " elif called_from == "leads": - context["url"] = protocol + "://" + domain subject = "New comment on Lead. " elif called_from == "opportunity": - context["url"] = protocol + "://" + domain subject = "New comment on Opportunity. " elif called_from == "cases": - context["url"] = protocol + "://" + domain subject = "New comment on Case. " elif called_from == "tasks": - context["url"] = protocol + "://" + domain subject = "New comment on Task. " elif called_from == "invoices": - context["url"] = protocol + "://" + domain subject = "New comment on Invoice. " elif called_from == "events": - context["url"] = protocol + "://" + domain subject = "New comment on Event. " + if subject: + context["url"] = settings.DOMAIN_NAME else: context["url"] = "" # subject = 'Django CRM : comment ' @@ -128,7 +123,7 @@ def send_email_user_mentions( @app.task def send_email_user_status( - user_id, status_changed_user="", domain="demo.django-crm.io", protocol="http" + user_id, status_changed_user="", ): """ Send Mail To Users Regarding their status i.e active or inactive """ user = User.objects.filter(id=user_id).first() @@ -136,12 +131,9 @@ def send_email_user_status( context = {} context["message"] = "deactivated" context["email"] = user.email - if user.has_sales_access: - context["url"] = protocol + "://" + domain + "/" - elif user.has_marketing_access: - context["url"] = protocol + "://" + domain + "/marketing" - else: - context["url"] = protocol + "://" + domain + "/" + context["url"] = settings.DOMAIN_NAME + if user.has_marketing_access: + context["url"] = context["url"] + "/marketing" if user.is_active: context["message"] = "activated" context["status_changed_user"] = status_changed_user @@ -165,7 +157,7 @@ def send_email_user_status( @app.task def send_email_user_delete( - user_email, deleted_by="", domain="demo.django-crm.io", protocol="http" + user_email, deleted_by="", ): """ Send Mail To Users When their account is deleted """ if user_email: @@ -186,7 +178,7 @@ def send_email_user_delete( @app.task def resend_activation_link_to_user( - user_email="", domain="demo.django-crm.io", protocol="http" + user_email="", ): """ Send Mail To Users When their account is created """ @@ -196,7 +188,7 @@ def resend_activation_link_to_user( if user_obj: context = {} context["user_email"] = user_email - context["url"] = protocol + "://" + domain + context["url"] = settings.DOMAIN_NAME context["uid"] = (urlsafe_base64_encode(force_bytes(user_obj.pk)),) context["token"] = account_activation_token.make_token(user_obj) time_delta_two_hours = datetime.datetime.strftime( @@ -215,7 +207,7 @@ def resend_activation_link_to_user( context["token"], activation_key, ) - recipients = [] + recipients = [context["complete_url"]] recipients.append(user_email) subject = "Welcome to Django CRM" html_content = render_to_string("user_status_in.html", context=context) @@ -226,14 +218,12 @@ def resend_activation_link_to_user( @app.task -def send_email_to_reset_password( - user_email, domain="demo.django-crm.io", protocol="http" -): +def send_email_to_reset_password(user_email): """ Send Mail To Users When their account is created """ user = User.objects.filter(email=user_email).first() context = {} context["user_email"] = user_email - context["url"] = protocol + "://" + domain + context["url"] = settings.DOMAIN_NAME context["uid"] = (urlsafe_base64_encode(force_bytes(user.pk)),) context["token"] = default_token_generator.make_token(user) context["token"] = context["token"] diff --git a/common/utils.py b/common/utils.py index 26181b6..040606a 100644 --- a/common/utils.py +++ b/common/utils.py @@ -1,12 +1,5 @@ import pytz -from datetime import datetime -from datetime import datetime, timedelta - from django.utils.translation import ugettext_lazy as _ -from django.conf import settings -from django.forms.models import model_to_dict -from .custom_auth import BaseJSONWebTokenAuthentication -from rest_framework.authentication import get_authorization_header def jwt_payload_handler(user): diff --git a/common/views.py b/common/views.py index b3b7a84..adfc78d 100644 --- a/common/views.py +++ b/common/views.py @@ -1,7 +1,6 @@ from django.conf import settings from drf_yasg.utils import swagger_auto_schema -from django.contrib.sites.shortcuts import get_current_site -from django.shortcuts import get_object_or_404, redirect +from django.shortcuts import get_object_or_404 from rest_framework import status from accounts.serializer import AccountSerializer from contacts.serializer import ContactSerializer @@ -27,7 +26,6 @@ resend_activation_link_to_user, send_email_to_new_user, send_email_user_delete, - send_email_user_status, send_email_to_reset_password, ) from django.utils.translation import gettext as _ @@ -36,21 +34,16 @@ from rest_framework.response import Response from rest_framework_jwt.serializers import jwt_encode_handler from common.utils import jwt_payload_handler -from rest_framework.exceptions import APIException from rest_framework.permissions import IsAuthenticated from rest_framework.pagination import LimitOffsetPagination from common.custom_auth import JSONWebTokenAuthentication from common import swagger_params from django.db.models import Q -from rest_framework.decorators import api_view import json -from django.contrib.auth.tokens import default_token_generator from django.utils.encoding import force_text from django.utils.http import urlsafe_base64_decode from common.token_generator import account_activation_token -from common.models import Profile from django.utils import timezone -from django.conf import settings from common.utils import COUNTRIES @@ -63,18 +56,14 @@ class GetTeamsAndUsersView(APIView): tags=["Users"], manual_parameters=swagger_params.organization_params ) def get(self, request, *args, **kwargs): - if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: - return Response( - {"error": True, "errors": "Permission Denied"}, - status=status.HTTP_403_FORBIDDEN, - ) data = {} - teams = Teams.objects.filter(org=request.org) + teams = Teams.objects.filter(org=request.org).order_by('-id') teams_data = TeamsSerializer(teams, many=True).data - users = Profile.objects.filter(is_active=True, org=request.org) - users_data = ProfileSerializer(users, many=True).data + profiles = Profile.objects.filter( + is_active=True, org=request.org).order_by('user__email') + profiles_data = ProfileSerializer(profiles, many=True).data data["teams"] = teams_data - data["users_data"] = users_data + data["profiles"] = profiles_data return Response(data) @@ -90,39 +79,35 @@ def get_object(self, pk): tags=["Users"], manual_parameters=swagger_params.organization_params ) def get(self, request, pk, format=None): - user_obj = self.get_object(pk) + profile_obj = self.get_object(pk) if ( self.request.profile.role != "ADMIN" and not self.request.profile.is_admin - and self.request.profile.id != user_obj.id + and self.request.profile.id != profile_obj.id ): return Response( {"error": True, "errors": "Permission Denied"}, status=status.HTTP_403_FORBIDDEN, ) - if user_obj.org != request.org: + if profile_obj.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, - status=status.HTTP_404_NOT_FOUND, + status=status.HTTP_403_FORBIDDEN, ) - users_data = [] - for each in Profile.objects.filter(org=request.org, is_active=True): - assigned_dict = {} - assigned_dict["id"] = each.id - assigned_dict["name"] = each.user.first_name - users_data.append(assigned_dict) + assigned_data = Profile.objects.filter( + org=request.org, is_active=True).values('id', 'user__first_name') context = {} - context["user_obj"] = ProfileSerializer(user_obj).data - opportunity_list = Opportunity.objects.filter(assigned_to=user_obj) + context["profile_obj"] = ProfileSerializer(profile_obj).data + opportunity_list = Opportunity.objects.filter(assigned_to=profile_obj) context["opportunity_list"] = OpportunitySerializer( opportunity_list, many=True ).data - contacts = Contact.objects.filter(assigned_to=user_obj) + contacts = Contact.objects.filter(assigned_to=profile_obj) context["contacts"] = ContactSerializer(contacts, many=True).data - cases = Case.objects.filter(assigned_to=user_obj) + cases = Case.objects.filter(assigned_to=profile_obj) context["cases"] = CaseSerializer(cases, many=True).data - context["assigned_data"] = users_data - comments = user_obj.user_comments.all() + context["assigned_data"] = assigned_data + comments = profile_obj.user_comments.all() context["comments"] = CommentSerializer(comments, many=True).data context["countries"] = COUNTRIES return Response( @@ -151,7 +136,7 @@ def put(self, request, pk, format=None): if profile.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, - status=status.HTTP_404_NOT_FOUND, + status=status.HTTP_403_FORBIDDEN, ) serializer = CreateUserSerializer( data=params, instance=profile.user, org=request.org) @@ -178,21 +163,6 @@ def put(self, request, pk, format=None): user.username = user.first_name user.save() profile = profile_serializer.save() - if self.request.profile.role == "ADMIN": - if params.getlist("teams"): - user_teams = profile.user_teams.all() - - team_obj = Teams.objects.filter(org=request.org) - for team in params.getlist("teams"): - try: - team_obj = team_obj.filter(id=team).first() - if team_obj != user_teams: - team_obj.users.add(profile) - except: - return Response( - {"detail": "No such Team Available"}, - status=status.HTTP_404_NOT_FOUND, - ) return Response( {"error": False, "message": "User Updated Successfully"}, status=status.HTTP_200_OK, @@ -221,8 +191,6 @@ def delete(self, request, pk, format=None): send_email_user_delete.delay( self.object.user.email, deleted_by=deleted_by, - domain=settings.DOMAIN_NAME, - protocol=request.scheme, ) self.object.delete() return Response({"status": "success"}, status=status.HTTP_200_OK) @@ -273,24 +241,22 @@ def get(self, request, format=None): Q(status="converted") | Q(status="closed")) opportunities = Opportunity.objects.filter(org=request.org) - if self.request.profile.role == "ADMIN" or self.request.user.is_superuser: - pass - else: + if self.request.profile.role != "ADMIN" and not self.request.user.is_superuser: accounts = accounts.filter( - Q(assigned_to__id__in=[self.request.profile.id]) - | Q(created_by=self.request.profile.id) + Q(assigned_to=self.request.profile) + | Q(created_by=self.request.profile) ) contacts = contacts.filter( - Q(assigned_to__id__in=[self.request.profile.id]) - | Q(created_by=self.request.profile.id) + Q(assigned_to__id__in=self.request.profile) + | Q(created_by=self.request.profile) ) leads = leads.filter( - Q(assigned_to__id__in=[self.request.profile.id]) - | Q(created_by=self.request.profile.id) + Q(assigned_to__id__in=self.request.profile) + | Q(created_by=self.request.profile) ).exclude(status="closed") opportunities = opportunities.filter( - Q(assigned_to__id__in=[self.request.profile.id]) - | Q(created_by=self.request.profile.id) + Q(assigned_to__id__in=self.request.profile) + | Q(created_by=self.request.profile) ) context = {} context["accounts_count"] = accounts.count() @@ -342,14 +308,13 @@ def post(self, request, format=None): "error": False, } return Response(response_data, status=status.HTTP_200_OK) - else: - password_field = "doesnot match" - msg = _("Email and password {password_field}") - msg = msg.format(password_field=password_field) - return Response( - {"error": True, "errors": msg}, - status=status.HTTP_400_BAD_REQUEST, - ) + password_field = "doesnot match" + msg = _("Email and password {password_field}") + msg = msg.format(password_field=password_field) + return Response( + {"error": True, "errors": msg}, + status=status.HTTP_400_BAD_REQUEST, + ) class RegistrationView(APIView): @@ -381,13 +346,9 @@ def post(self, request, format=None): if created: user.is_active = False user.save() - protocol = request.scheme - current_site = get_current_site(self.request) send_email_to_new_user.delay( profile.id, org.id, - domain=current_site.domain, - protocol=protocol, ) return Response( {"error": False, "message": "User created Successfully."}, @@ -466,15 +427,11 @@ def post(self, request, format=None): 'role'), address=address_obj, org=request.org, - ), + ) - current_site = get_current_site(self.request) - protocol = request.scheme send_email_to_new_user.delay( - profile[0].id, + profile.id, request.org.id, - domain=current_site.domain, - protocol=protocol, ) return Response( {"error": False, "message": "User Created Successfully"}, @@ -490,56 +447,64 @@ def get(self, request, format=None): {"error": True, "errors": "Permission Denied"}, status=status.HTTP_403_FORBIDDEN, ) + queryset = Profile.objects.filter(org=request.org).order_by('-id') + params = ( + self.request.query_params + if len(self.request.data) == 0 + else self.request.data + ) + if params: + if params.get("email"): + queryset = queryset.filter( + user__email__icontains=params.get("email")) + if params.get("role"): + queryset = queryset.filter(role=params.get("role")) + if params.get("status"): + queryset = queryset.filter(is_active=params.get("status")) + + context = {} + queryset_active_users = queryset.filter(is_active=True) + results_active_users = self.paginate_queryset( + queryset_active_users.distinct(), self.request, view=self + ) + active_users = ProfileSerializer( + results_active_users, many=True).data + if results_active_users: + offset = queryset_active_users.filter( + id__gte=results_active_users[-1].id).count() + if offset == queryset_active_users.count(): + offset = None else: - queryset = Profile.objects.filter(org=request.org) - params = ( - self.request.query_params - if len(self.request.data) == 0 - else self.request.data - ) - if params: - if params.get("email"): - queryset = queryset.filter( - user__email__icontains=params.get("email")) - if params.get("role"): - queryset = queryset.filter(role=params.get("role")) - if params.get("status"): - queryset = queryset.filter(is_active=params.get("status")) - - context = {} - queryset_active_users = queryset.filter(is_active=True) - results_active_users = self.paginate_queryset( - queryset_active_users.distinct(), self.request, view=self - ) - active_users = ProfileSerializer( - results_active_users, many=True).data - context["per_page"] = 10 - context["active_users"] = { - "active_users_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, - "active_users": active_users, - } + offset = 0 + context["active_users"] = { + "active_users_count": self.count, + "active_users": active_users, + "offset": offset + } - queryset_inactive_users = queryset.filter(is_active=False) - results_inactive_users = self.paginate_queryset( - queryset_inactive_users.distinct(), self.request, view=self - ) - inactive_users = ProfileSerializer( - results_inactive_users, many=True).data - context["inactive_users"] = { - "inactive_users_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, - "inactive_users": inactive_users, - } + queryset_inactive_users = queryset.filter(is_active=False) + results_inactive_users = self.paginate_queryset( + queryset_inactive_users.distinct(), self.request, view=self + ) + inactive_users = ProfileSerializer( + results_inactive_users, many=True).data + if results_inactive_users: + offset = queryset_inactive_users.filter( + id__gte=results_inactive_users[-1].id).count() + if offset == queryset_inactive_users.count(): + offset = None + else: + offset = 0 + context["inactive_users"] = { + "inactive_users_count": self.count, + "inactive_users": inactive_users, + "offset": offset + } - context["admin_email"] = settings.ADMIN_EMAIL - context["roles"] = ROLES - context["status"] = [("True", "Active"), ("False", "In Active")] - return Response(context) + context["admin_email"] = settings.ADMIN_EMAIL + context["roles"] = ROLES + context["status"] = [("True", "Active"), ("False", "In Active")] + return Response(context) class DocumentListView(APIView, LimitOffsetPagination): @@ -553,7 +518,8 @@ def get_context_data(self, **kwargs): if len(self.request.data) == 0 else self.request.data ) - queryset = self.model.objects.filter(org=self.request.org) + queryset = self.model.objects.filter( + org=self.request.org).order_by('-id') if self.request.user.is_superuser or self.request.profile.role == "ADMIN": queryset = queryset else: @@ -607,13 +573,17 @@ def get_context_data(self, **kwargs): ) documents_active = DocumentSerializer( results_documents_active, many=True).data - context["per_page"] = 10 + if results_documents_active: + offset = queryset_documents_active.filter( + id__gte=results_documents_active[-1].id).count() + if offset == queryset_documents_active.count(): + offset = None + else: + offset = 0 context["documents_active"] = { "documents_active_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, "documents_active": documents_active, + "offset": offset } queryset_documents_inactive = queryset.filter(status="inactive") @@ -623,13 +593,17 @@ def get_context_data(self, **kwargs): documents_inactive = DocumentSerializer( results_documents_inactive, many=True ).data - + if results_documents_inactive: + offset = queryset_documents_inactive.filter( + id__gte=results_documents_active[-1].id).count() + if offset == queryset_documents_inactive.count(): + offset = None + else: + offset = 0 context["documents_inactive"] = { "documents_inactive_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, "documents_inactive": documents_inactive, + "offset": offset } context["users"] = ProfileSerializer(profiles, many=True).data @@ -657,32 +631,17 @@ def post(self, request, *args, **kwargs): document_file=request.FILES.get("document_file"), ) if params.get("shared_to"): - assinged_to_users_ids = json.loads(params.get("shared_to")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter( - id=user_id, org=request.org) - if user.exists(): - doc.shared_to.add(user_id) - else: - doc.delete() - return Response( - {"error": True, "errors": "Enter Valid User"}, - status=status.HTTP_400_BAD_REQUEST, - ) - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter( - id=team, org=request.org) - if teams_ids.exists(): - doc.teams.add(team) - else: - doc.delete() - return Response( - {"error": True, "errors": "Enter Valid Team"}, - status=status.HTTP_400_BAD_REQUEST, - ) + assinged_to_list = json.loads(params.get("shared_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org, is_active=True) + if profiles: + doc.shared_to.add(*profiles) + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + if teams: + doc.teams.add(*teams) return Response( {"error": False, "message": "Document Created Successfully"}, @@ -816,32 +775,19 @@ def put(self, request, pk, format=None): ) doc.shared_to.clear() if params.get("shared_to"): - assinged_to_users_ids = json.loads(params.get("shared_to")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter( - id=user_id, org=request.org) - if user.exists(): - doc.shared_to.add(user_id) - else: - return Response( - {"error": True, "errors": "Enter Valid User"}, - status=status.HTTP_400_BAD_REQUEST, - ) - - if self.request.profile.role == "ADMIN": - doc.teams.clear() - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter( - id=team, org=request.org) - if teams_ids.exists(): - doc.teams.add(team) - else: - return Response( - {"error": True, "errors": "Enter Valid Team"}, - status=status.HTTP_400_BAD_REQUEST, - ) + assinged_to_list = json.loads(params.get("shared_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org, is_active=True) + if profiles: + doc.shared_to.add(*profiles) + + doc.teams.clear() + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + if teams: + doc.teams.add(*teams) return Response( {"error": False, "message": "Document Updated Successfully"}, status=status.HTTP_200_OK, @@ -867,18 +813,16 @@ def post(self, request, format=None): {"error": True, "errors": "Please activate account to proceed."}, status=status.HTTP_406_NOT_ACCEPTABLE, ) - protocol = self.request.scheme send_email_to_reset_password.delay( - user.email, protocol=protocol, domain=settings.DOMAIN_NAME + user.email ) data = { "error": False, "message": "We have sent you an email. please reset password", } return Response(data, status=status.HTTP_200_OK) - else: - data = {"error": True, "errors": serializer.errors} - response_status = status.HTTP_400_BAD_REQUEST + data = {"error": True, "errors": serializer.errors} + response_status = status.HTTP_400_BAD_REQUEST return Response(data, status=response_status) @@ -1096,11 +1040,8 @@ def post(self, request, uid, token, activation_key, format=None): profile = get_object_or_404(Profile, activation_key=activation_key) if profile.user: if timezone.now() > profile.key_expires: - protocol = request.scheme resend_activation_link_to_user.delay( profile.user.email, - domain=settings.DOMAIN_NAME, - protocol=protocol, ) return Response( { @@ -1127,11 +1068,10 @@ def post(self, request, uid, token, activation_key, format=None): }, status=status.HTTP_200_OK, ) - else: - return Response( - {"error": True, "errors": "Activation link is invalid!"}, - status=status.HTTP_400_BAD_REQUEST, - ) + return Response( + {"error": True, "errors": "Activation link is invalid!"}, + status=status.HTTP_400_BAD_REQUEST, + ) class ResendActivationLinkView(APIView): @@ -1147,11 +1087,8 @@ def post(self, request, format=None): {"error": False, "message": "Account is active. Please login"}, status=status.HTTP_200_OK, ) - protocol = request.scheme resend_activation_link_to_user.delay( user.email, - domain=settings.DOMAIN_NAME, - protocol=protocol, ) data = { "error": False, @@ -1176,34 +1113,3 @@ def get(self, request): 'companies': OrganizationSerializer( companies, many=True).data}, status=status.HTTP_200_OK) - - -# class UsersDelete(APIView): - -# authentication_classes = (JSONWebTokenAuthentication,) -# permission_classes = (IsAuthenticated,) - -# @swagger_auto_schema( -# tags=["Users"], manual_parameters=swagger_params.users_delete_params, -# operation_description="To delete multiple users", -# ) -# def post(self, request, *args, **kwargs): -# if self.request.user.role == "ADMIN" or self.request.user.is_superuser: -# params = request.query_params if len(request.data) == 0 else request.data -# users_list = json.loads(params.get("users_list")) -# users = User.objects.filter( -# id__in = users_list -# ) -# users.delete() -# return Response( -# { -# "error": False, -# "message": "Users deleted successfully", -# }, -# status=status.HTTP_200_OK, -# ) -# else: -# return Response( -# {"error": True, "errors": "Permission Denied"}, -# status=status.HTTP_403_FORBIDDEN, -# ) diff --git a/contacts/serializer.py b/contacts/serializer.py index ad18e4e..44b39e1 100644 --- a/contacts/serializer.py +++ b/contacts/serializer.py @@ -59,9 +59,8 @@ class Meta: class CreateContactSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): - contact_view = kwargs.pop("contact", False) request_obj = kwargs.pop("request_obj", None) - super(CreateContactSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.org = request_obj.org def validate_first_name(self, first_name): diff --git a/contacts/tasks.py b/contacts/tasks.py index 5ce5e19..db341ba 100644 --- a/contacts/tasks.py +++ b/contacts/tasks.py @@ -1,9 +1,9 @@ from celery import Celery +from django.conf import settings from django.core.mail import EmailMessage -from django.shortcuts import reverse from django.template.loader import render_to_string -from common.models import User, Profile +from common.models import Profile from contacts.models import Contact app = Celery("redis://") @@ -11,7 +11,7 @@ @app.task def send_email_to_assigned_user( - recipients, contact_id, domain="demo.django-crm.io", protocol="http" + recipients, contact_id ): """ Send Mail To Users When they are assigned to a contact """ contact = Contact.objects.get(id=contact_id) @@ -22,7 +22,7 @@ def send_email_to_assigned_user( if profile: recipients_list.append(profile.user.email) context = {} - context["url"] = protocol + "://" + domain + context["url"] = settings.DOMAIN_NAME context["user"] = profile.user context["contact"] = contact context["created_by"] = created_by diff --git a/contacts/views.py b/contacts/views.py index ac8884f..ee4a7bf 100644 --- a/contacts/views.py +++ b/contacts/views.py @@ -1,5 +1,5 @@ from rest_framework import status -from common.models import User, Attachments, Comment +from common.models import Attachments, Comment from contacts.models import Contact, Profile from teams.models import Teams from django.db.models import Q @@ -14,17 +14,13 @@ from rest_framework.views import APIView from common.utils import COUNTRIES from common.serializer import ( - ProfileSerializer, CommentSerializer, AttachmentsSerializer, BillingAddressSerializer, ) -from teams.serializer import TeamsSerializer from tasks.serializer import TaskSerializer -from django.contrib.sites.shortcuts import get_current_site from contacts.tasks import send_email_to_assigned_user import json -from django.conf import settings class ContactsListView(APIView, LimitOffsetPagination): @@ -38,63 +34,53 @@ def get_context_data(self, **kwargs): if len(self.request.data) == 0 else self.request.data ) - queryset = self.model.objects.filter(org=self.request.org).order_by("-created_on") + queryset = self.model.objects.filter( + org=self.request.org).order_by("-id") if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: queryset = queryset.filter( - Q(assigned_to__in=[self.request.profile]) | Q(created_by=self.request.profile) + Q(assigned_to__in=[self.request.profile]) | Q( + created_by=self.request.profile) ).distinct() - request_post = params - if request_post: - if request_post.get("name"): + if params: + if params.get("name"): queryset = queryset.filter( - first_name__icontains=request_post.get("name") + first_name__icontains=params.get("name") ) - if request_post.get("city"): + if params.get("city"): queryset = queryset.filter( - address__city__icontains=request_post.get("city") + address__city__icontains=params.get("city") ) - if request_post.get("phone"): - queryset = queryset.filter(mobile_number__icontains=request_post.get("phone")) - if request_post.get("email"): - queryset = queryset.filter(primary_email__icontains=request_post.get("email")) - if request_post.getlist("assigned_to"): + if params.get("phone"): queryset = queryset.filter( - assigned_to__id__in=json.loads(request_post.get("assigned_to")) + mobile_number__icontains=params.get("phone")) + if params.get("email"): + queryset = queryset.filter( + primary_email__icontains=params.get("email")) + if params.getlist("assigned_to"): + queryset = queryset.filter( + assigned_to__id__in=json.loads(params.get("assigned_to")) ).distinct() context = {} - search = False - if ( - params.get("first_name") - or params.get("city") - or params.get("phone") - or params.get("email") - or params.get("assigned_to") - ): - search = True - context["search"] = search results_contact = self.paginate_queryset( queryset.distinct(), self.request, view=self ) - profiles = Profile.objects.filter(org=self.request.org, is_active=True) contacts = ContactSerializer(results_contact, many=True).data - context["per_page"] = 10 + if results_contact: + offset = queryset.filter(id__gte=results_contact[-1].id).count() + if offset == queryset.count(): + offset = None + else: + offset = 0 context.update( { "contacts_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, + "offset": offset } ) context["contact_obj_list"] = contacts - context["users"] = ProfileSerializer(profiles.order_by("user__email"), - many=True, - ).data context["countries"] = COUNTRIES - context["teams"] = TeamsSerializer(Teams.objects.filter(org=self.request.org), many=True).data context["per_page"] = params.get("per_page") - context["assignedto_list"] = ProfileSerializer(profiles, many=True).data return context @swagger_auto_schema( @@ -108,9 +94,10 @@ def get(self, request, *args, **kwargs): tags=["contacts"], manual_parameters=swagger_params.contact_create_post_params ) def post(self, request, *args, **kwargs): - params = request.query_params if len(request.data) == 0 else request.data + params = request.query_params if len( + request.data) == 0 else request.data contact_serializer = CreateContactSerializer( - data=params, request_obj=request, contact=True + data=params, request_obj=request ) address_serializer = BillingAddressSerializer(data=params) @@ -127,51 +114,32 @@ def post(self, request, *args, **kwargs): # if contact_serializer.is_valid() and address_serializer.is_valid(): address_obj = address_serializer.save() contact_obj = contact_serializer.save( - date_of_birth = params.get("date_of_birth") + date_of_birth=params.get("date_of_birth") ) contact_obj.address = address_obj contact_obj.created_by = self.request.profile contact_obj.org = request.org contact_obj.save() - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter(id=team, org=request.org) - if teams_ids.exists(): - contact_obj.teams.add(team) - else: - contact_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - assinged_to_users_ids = json.loads(params.get("assigned_to")) - for user_id in assinged_to_users_ids: - profile = Profile.objects.filter(id=user_id, org=request.org) - if profile.exists(): - contact_obj.assigned_to.add(profile) - else: - contact_obj.delete() - data["assigned_to"] = "Please enter valid user" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - assigned_to_list = list( + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + contact_obj.teams.add(*teams) + + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org) + contact_obj.assigned_to.add(*profiles) + + recipients = list( contact_obj.assigned_to.all().values_list("id", flat=True) ) - current_site = get_current_site(self.request) - recipients = assigned_to_list send_email_to_assigned_user.delay( recipients, contact_obj.id, - domain=current_site.domain, - protocol=self.request.scheme, ) if request.FILES.get("contact_attachment"): @@ -199,7 +167,8 @@ def get_object(self, pk): tags=["contacts"], manual_parameters=swagger_params.contact_create_post_params ) def put(self, request, pk, format=None): - params = request.query_params if len(request.data) == 0 else request.data + params = request.query_params if len( + request.data) == 0 else request.data contact_obj = self.get_object(pk=pk) address_obj = contact_obj.address if contact_obj.org != request.org: @@ -210,7 +179,8 @@ def put(self, request, pk, format=None): contact_serializer = CreateContactSerializer( data=params, instance=contact_obj, request_obj=request, contact=True ) - address_serializer = BillingAddressSerializer(data=params, instance=address_obj) + address_serializer = BillingAddressSerializer( + data=params, instance=address_obj) data = {} if not contact_serializer.is_valid(): data["contact_errors"] = contact_serializer.errors @@ -238,39 +208,25 @@ def put(self, request, pk, format=None): ) address_obj = address_serializer.save() contact_obj = contact_serializer.save( - date_of_birth = params.get("date_of_birth") + date_of_birth=params.get("date_of_birth") ) contact_obj.address = address_obj contact_obj.save() contact_obj = contact_serializer.save() - if self.request.profile.role == "ADMIN": - contact_obj.teams.clear() - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter(id=team, org=request.org) - if teams_ids.exists(): - contact_obj.teams.add(team) - else: - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - contact_obj.assigned_to.clear() - if params.get("assigned_to"): - assinged_to_users_ids = json.loads(params.get("assigned_to")) - for user_id in assinged_to_users_ids: - profile = Profile.objects.filter(id=user_id, org=request.org) - if profile.exists(): - contact_obj.assigned_to.add(user_id) - else: - data["assigned_to"] = "Please enter valid user" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + contact_obj.teams.clear() + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + contact_obj.teams.add(*teams) + + contact_obj.assigned_to.clear() + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org) + contact_obj.assigned_to.add(*profiles) previous_assigned_to_users = list( contact_obj.assigned_to.all().values_list("id", flat=True) @@ -279,18 +235,17 @@ def put(self, request, pk, format=None): assigned_to_list = list( contact_obj.assigned_to.all().values_list("id", flat=True) ) - recipients = list(set(assigned_to_list) - set(previous_assigned_to_users)) - current_site = get_current_site(self.request) + recipients = list(set(assigned_to_list) - + set(previous_assigned_to_users)) send_email_to_assigned_user.delay( recipients, contact_obj.id, - domain=current_site.domain, - protocol=request.scheme, ) if request.FILES.get("contact_attachment"): attachment = Attachments() attachment.created_by = request.profile - attachment.file_name = request.FILES.get("contact_attachment").name + attachment.file_name = request.FILES.get( + "contact_attachment").name attachment.contact = contact_obj attachment.attachment = request.FILES.get("contact_attachment") attachment.save() @@ -310,7 +265,8 @@ def get(self, request, pk, format=None): assigned_to.id for assigned_to in contact_obj.assigned_to.all() ] user_assigned_accounts = set( - self.request.profile.account_assigned_users.values_list("id", flat=True) + self.request.profile.account_assigned_users.values_list( + "id", flat=True) ) contact_accounts = set( contact_obj.account_contacts.values_list("id", flat=True) @@ -336,22 +292,21 @@ def get(self, request, pk, format=None): assigned_data.append(assigned_dict) if self.request.profile.is_admin or self.request.profile.role == "ADMIN": - users_mention = list(Profile.objects.filter(is_active=True, org=request.org).values("user__username")) + users_mention = list(Profile.objects.filter( + is_active=True, org=request.org).values("user__username")) elif self.request.profile != contact_obj.created_by: - users_mention = [{"username": contact_obj.created_by.user.username}] + users_mention = [ + {"username": contact_obj.created_by.user.username}] else: - users_mention = list(contact_obj.assigned_to.all().values("username")) + users_mention = list( + contact_obj.assigned_to.all().values("username")) if request.profile == contact_obj.created_by: user_assgn_list.append(self.request.profile.id) - context["address_obj"] = BillingAddressSerializer(contact_obj.address).data - context["users"] = ProfileSerializer( - Profile.objects.filter(is_active=True, org=request.org).order_by("user__email"), - many=True, - ).data + context["address_obj"] = BillingAddressSerializer( + contact_obj.address).data context["countries"] = COUNTRIES - context["teams"] = TeamsSerializer(Teams.objects.filter(org=request.org), many=True).data context.update( { "comments": CommentSerializer( @@ -391,10 +346,9 @@ def delete(self, request, pk, format=None): }, status=status.HTTP_403_FORBIDDEN, ) - else: - if self.object.address_id: - self.object.address.delete() - self.object.delete() + if self.object.address_id: + self.object.address.delete() + self.object.delete() return Response( {"error": False, "message": "Contact Deleted Successfully."}, status=status.HTTP_200_OK, @@ -435,9 +389,11 @@ def post(self, request, pk, **kwargs): if self.request.FILES.get("contact_attachment"): attachment = Attachments() attachment.created_by = self.request.profile - attachment.file_name = self.request.FILES.get("contact_attachment").name + attachment.file_name = self.request.FILES.get( + "contact_attachment").name attachment.contact = self.contact_obj - attachment.attachment = self.request.FILES.get("contact_attachment") + attachment.attachment = self.request.FILES.get( + "contact_attachment") attachment.save() comments = Comment.objects.filter(contact__id=self.contact_obj.id).order_by( @@ -468,7 +424,8 @@ def get_object(self, pk): tags=["contacts"], manual_parameters=swagger_params.contact_comment_edit_params ) def put(self, request, pk, format=None): - params = request.query_params if len(request.data) == 0 else request.data + params = request.query_params if len( + request.data) == 0 else request.data obj = self.get_object(pk) if ( request.profile.role == "ADMIN" @@ -476,25 +433,23 @@ def put(self, request, pk, format=None): or request.profile == obj.commented_by ): serializer = CommentSerializer(obj, data=params) - if params.get("comment"): - if serializer.is_valid(): - serializer.save() - return Response( - {"error": False, "message": "Comment Submitted"}, - status=status.HTTP_200_OK, - ) + if serializer.is_valid(): + serializer.save() return Response( - {"error": True, "errors": serializer.errors}, - status=status.HTTP_400_BAD_REQUEST, + {"error": False, "message": "Comment Submitted"}, + status=status.HTTP_200_OK, ) - else: return Response( - { - "error": True, - "errors": "You don't have permission to edit this Comment", - }, - status=status.HTTP_403_FORBIDDEN, + {"error": True, "errors": serializer.errors}, + status=status.HTTP_400_BAD_REQUEST, ) + return Response( + { + "error": True, + "errors": "You don't have permission to edit this Comment", + }, + status=status.HTTP_403_FORBIDDEN, + ) @swagger_auto_schema(tags=["contacts"], manual_parameters=swagger_params.organization_params) def delete(self, request, pk, format=None): @@ -509,14 +464,13 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Comment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) class ContactAttachmentView(APIView): @@ -537,11 +491,10 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Attachment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to delete this Attachment", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to delete this Attachment", + }, + status=status.HTTP_403_FORBIDDEN, + ) diff --git a/crm/server_settings.py b/crm/server_settings.py index 75201f7..1822f77 100644 --- a/crm/server_settings.py +++ b/crm/server_settings.py @@ -4,8 +4,6 @@ DEBUG = False -DOMAIN_NAME = "bottlecrm.com" - AWS_STORAGE_BUCKET_NAME = AWS_BUCKET_NAME = os.getenv("AWS_BUCKET_NAME", "") AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID", "") AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY", "") diff --git a/crm/settings.py b/crm/settings.py index 825a7d2..0e42f0e 100644 --- a/crm/settings.py +++ b/crm/settings.py @@ -1,7 +1,5 @@ import os from dotenv import load_dotenv -from pathlib import Path -from celery.schedules import crontab from corsheaders.defaults import default_headers # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -131,7 +129,6 @@ STATIC_URL = "/static/" ENV_TYPE = os.getenv("ENV_TYPE", "dev") if ENV_TYPE == "dev": - DOMAIN_NAME = "localhost:8000" # SESSION_COOKIE_DOMAIN = "localhost:8000" MEDIA_ROOT = os.path.join(BASE_DIR, "media") @@ -246,3 +243,5 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField" STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" + +DOMAIN_NAME = os.getenv("DOMAIN_NAME") diff --git a/emails/views.py b/emails/views.py index 30035c8..58e00c9 100644 --- a/emails/views.py +++ b/emails/views.py @@ -177,10 +177,8 @@ def email_sent_edit(request, pk): f.status = "sent" f.save() return HttpResponseRedirect(reverse("emails:list")) - else: - return render(request, "create_mail.html", {"form": form, "em": em}) - else: - form = EmailForm() + return render(request, "create_mail.html", {"form": form, "em": em}) + form = EmailForm() return render(request, "create_mail.html", {"form": form, "em": em}) diff --git a/env.md b/env.md index b324f75..030a5f5 100644 --- a/env.md +++ b/env.md @@ -3,6 +3,7 @@ SECRET_KEY ENV_TYPE="dev/live" DEBUG=True +DOMAIN_NAME # AWS AWS_BUCKET_NAME diff --git a/events/models.py b/events/models.py index 8b536aa..c0d77ad 100644 --- a/events/models.py +++ b/events/models.py @@ -1,7 +1,6 @@ import arrow from django.db import models -from django.utils.translation import pgettext_lazy from django.utils.translation import ugettext_lazy as _ from common.models import Org, Profile from contacts.models import Contact diff --git a/events/serializer.py b/events/serializer.py index 123ff35..4e2b809 100644 --- a/events/serializer.py +++ b/events/serializer.py @@ -8,7 +8,7 @@ ) from contacts.serializer import ContactSerializer from teams.serializer import TeamsSerializer -from datetime import date, datetime, timedelta +from datetime import datetime, timedelta class EventSerializer(serializers.ModelSerializer): diff --git a/events/tasks.py b/events/tasks.py index 20af82c..e5003ca 100644 --- a/events/tasks.py +++ b/events/tasks.py @@ -1,18 +1,15 @@ from celery import Celery from django.conf import settings from django.core.mail import EmailMessage -from django.shortcuts import reverse from django.template.loader import render_to_string - -from common.models import User -from contacts.models import Contact +from common.models import Profile from events.models import Event app = Celery("redis://") @app.task -def send_email(event_id, recipients, domain="demo.django-crm.io", protocol="http"): +def send_email(event_id, recipients): event = Event.objects.filter(id=event_id).first() subject = " Invitation for an event." context = {} @@ -20,7 +17,7 @@ def send_email(event_id, recipients, domain="demo.django-crm.io", protocol="http context["event_id"] = event_id context["event_created_by"] = event.created_by context["event_date_of_meeting"] = event.date_of_meeting - context["url"] = protocol + "://" + domain + context["url"] = settings.DOMAIN_NAME # recipients = event.assigned_to.filter(is_active=True) for profile_id in recipients: recipients_list = [] diff --git a/events/views.py b/events/views.py index f3c2446..80eb138 100644 --- a/events/views.py +++ b/events/views.py @@ -8,7 +8,6 @@ ProfileSerializer, CommentSerializer, AttachmentsSerializer, - CommentSerializer, ) from events import swagger_params from events.models import Event @@ -48,7 +47,7 @@ def get_context_data(self, **kwargs): if len(self.request.data) == 0 else self.request.data ) - queryset = self.model.objects.filter(org=self.request.org) + queryset = self.model.objects.filter(org=self.request.org).order_by('-id') contacts = Contact.objects.filter(org=self.request.org) if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: queryset = queryset.filter( @@ -75,47 +74,23 @@ def get_context_data(self, **kwargs): date_of_meeting=params.get("date_of_meeting") ) context = {} - search = False - if ( - params.get("name") - or params.get("created_by") - or params.get("assigned_users") - or params.get("date_of_meeting") - ): - search = True - context["search"] = search results_events = self.paginate_queryset( queryset, self.request, view=self) events = EventSerializer(results_events, many=True).data - - context["per_page"] = 10 + if results_events: + offset = queryset.filter(id__gte=results_events[-1].id).count() + if offset == queryset.count(): + offset = None + else: + offset = 0 context.update( { "events_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, + "offset": offset } ) - - if search: - context["events"] = events - return context - context["events"] = events - users = [] - profile_list = Profile.objects.filter( - is_active=True, org=self.request.org) - if self.request.profile.role == "ADMIN" or self.request.profile.is_admin: - profiles = profile_list.order_by("user__email") - else: - profiles = profile_list.filter( - role="ADMIN").order_by("user__email") context["recurring_days"] = WEEKDAYS - context["users"] = ProfileSerializer(profiles, many=True).data - if self.request.profile == "ADMIN": - context["teams_list"] = TeamsSerializer( - Teams.objects.filter(org=self.request.org), many=True).data context["contacts_list"] = ContactSerializer(contacts, many=True).data return context @@ -149,58 +124,32 @@ def post(self, request, *args, **kwargs): disabled=False, org=request.org ) + + if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter( - id=contact, org=request.org) - if obj_contact.exists(): - event_obj.contacts.add(contact) - else: - event_obj.delete() - data["contacts"] = "Please enter valid contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter( - id=team, org=request.org) - if teams_ids.exists(): - event_obj.teams.add(team) - else: - event_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if params.get("assigned_to"): - assinged_to_users_ids = json.loads( - params.get("assigned_to")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter( - id=user_id, org=request.org) - if user.exists(): - event_obj.assigned_to.add(user_id) - else: - event_obj.delete() - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + obj_contact = Contact.objects.filter( + id=params.get("contacts"), org=request.org) + event_obj.contacts.add(obj_contact) + + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + event_obj.teams.add(*teams) + + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org) + event_obj.assigned_to.add(*profiles) + assigned_to_list = list( event_obj.assigned_to.all().values_list("id", flat=True) ) send_email.delay( event_obj.id, assigned_to_list, - domain=request.get_host(), - protocol=request.scheme, ) if params.get("event_type") == "Recurring": recurring_days = params.get("recurring_days") @@ -238,58 +187,29 @@ def post(self, request, *args, **kwargs): ) if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter( - id=contact, org=request.org) - if obj_contact.exists(): - event.contacts.add(contact) - else: - event.delete() - data["contacts"] = "Please enter valid contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter( - id=team, org=request.org) - if teams_ids.exists(): - event.teams.add(team) - else: - event.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if params.get("assigned_to"): - assinged_to_users_ids = json.loads( - params.get("assigned_to") - ) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter( - id=user_id, org=request.org) - if user.exists(): - event.assigned_to.add(user_id) - else: - event.delete() - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + obj_contact = Contact.objects.filter( + id=params.get("contacts"), org=request.org) + event.contacts.add(obj_contact) + + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + event.teams.add(*teams) + + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org) + event.assigned_to.add(*profiles) + assigned_to_list = list( event.assigned_to.all().values_list("id", flat=True) ) send_email.delay( event.id, assigned_to_list, - domain=request.get_host(), - protocol=request.scheme, ) return Response( {"error": False, "message": "Event Created Successfully"}, @@ -495,55 +415,25 @@ def put(self, request, pk, **kwargs): event_obj.contacts.clear() if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter( - id=contact, org=request.org) - if obj_contact.exists(): - event_obj.contacts.add(contact) - else: - data["contacts"] = "Please enter valid Contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if self.request.profile.role == "ADMIN": - event_obj.teams.clear() - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter( - id=team, org=request.org) - if teams_ids.exists(): - event_obj.teams.add(team) - else: - event_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - else: - event_obj.teams.clear() - - event_obj.assigned_to.clear() - if params.get("assigned_to"): - assinged_to_users_ids = json.loads( - params.get("assigned_to")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter(id=user_id, org=request.org) - if user.exists(): - event_obj.assigned_to.add(user_id) - else: - event_obj.delete() - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - else: - event_obj.assigned_to.clear() + obj_contact = Contact.objects.filter( + id=params.get("contacts"), org=request.org) + event_obj.contacts.add(obj_contact) + + event_obj.teams.clear() + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + event_obj.teams.add(*teams) + + event_obj.assigned_to.clear() + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org) + event_obj.assigned_to.add(*profiles) + assigned_to_list = list( event_obj.assigned_to.all().values_list("id", flat=True) ) @@ -552,8 +442,6 @@ def put(self, request, pk, **kwargs): send_email.delay( event_obj.id, recipients, - domain=request.get_host(), - protocol=request.scheme, ) return Response( {"error": False, "message": "Event updated Successfully"}, @@ -606,25 +494,23 @@ def put(self, request, pk, format=None): or request.profile == obj.commented_by ): serializer = CommentSerializer(obj, data=params) - if params.get("comment"): - if serializer.is_valid(): - serializer.save() - return Response( - {"error": False, "message": "Comment Submitted"}, - status=status.HTTP_200_OK, - ) + if serializer.is_valid(): + serializer.save() return Response( - {"error": True, "errors": serializer.errors}, - status=status.HTTP_400_BAD_REQUEST, + {"error": False, "message": "Comment Submitted"}, + status=status.HTTP_200_OK, ) - else: return Response( - { - "error": True, - "errors": "You don't have Permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, + {"error": True, "errors": serializer.errors}, + status=status.HTTP_400_BAD_REQUEST, ) + return Response( + { + "error": True, + "errors": "You don't have Permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) @swagger_auto_schema( tags=["Events"], manual_parameters=swagger_params.organization_params @@ -641,14 +527,13 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Comment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have Permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have Permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) class EventAttachmentView(APIView): @@ -671,11 +556,10 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Attachment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have Permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have Permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) diff --git a/leads/forms.py b/leads/forms.py index 83fbb10..b4260d3 100644 --- a/leads/forms.py +++ b/leads/forms.py @@ -73,7 +73,7 @@ class LeadListForm(forms.Form): leads_file = forms.FileField(required=False) def __init__(self, *args, **kwargs): - super(LeadListForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["leads_file"].widget.attrs.update( { "accept": ".csv", diff --git a/leads/migrations/0018_auto_20211022_1731.py b/leads/migrations/0018_auto_20211022_1731.py new file mode 100644 index 0000000..99882e3 --- /dev/null +++ b/leads/migrations/0018_auto_20211022_1731.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.8 on 2021-10-22 12:01 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0037_alter_profile_org'), + ('leads', '0017_alter_lead_org'), + ] + + operations = [ + migrations.AddField( + model_name='lead', + name='industry', + field=models.CharField(blank=True, choices=[('ADVERTISING', 'ADVERTISING'), ('AGRICULTURE', 'AGRICULTURE'), ('APPAREL & ACCESSORIES', 'APPAREL & ACCESSORIES'), ('AUTOMOTIVE', 'AUTOMOTIVE'), ('BANKING', 'BANKING'), ('BIOTECHNOLOGY', 'BIOTECHNOLOGY'), ('BUILDING MATERIALS & EQUIPMENT', 'BUILDING MATERIALS & EQUIPMENT'), ('CHEMICAL', 'CHEMICAL'), ('COMPUTER', 'COMPUTER'), ('EDUCATION', 'EDUCATION'), ('ELECTRONICS', 'ELECTRONICS'), ('ENERGY', 'ENERGY'), ('ENTERTAINMENT & LEISURE', 'ENTERTAINMENT & LEISURE'), ('FINANCE', 'FINANCE'), ('FOOD & BEVERAGE', 'FOOD & BEVERAGE'), ('GROCERY', 'GROCERY'), ('HEALTHCARE', 'HEALTHCARE'), ('INSURANCE', 'INSURANCE'), ('LEGAL', 'LEGAL'), ('MANUFACTURING', 'MANUFACTURING'), ('PUBLISHING', 'PUBLISHING'), ('REAL ESTATE', 'REAL ESTATE'), ('SERVICE', 'SERVICE'), ('SOFTWARE', 'SOFTWARE'), ('SPORTS', 'SPORTS'), ('TECHNOLOGY', 'TECHNOLOGY'), ('TELECOMMUNICATIONS', 'TELECOMMUNICATIONS'), ('TELEVISION', 'TELEVISION'), ('TRANSPORTATION', 'TRANSPORTATION'), ('VENTURE CAPITAL', 'VENTURE CAPITAL')], max_length=255, null=True, verbose_name='Industry Type'), + ), + migrations.AddField( + model_name='lead', + name='skype_ID', + field=models.CharField(blank=True, max_length=100, null=True), + ), + migrations.AlterField( + model_name='lead', + name='source', + field=models.CharField(blank=True, choices=[('call', 'Call'), ('email', 'Email'), ('existing customer', 'Existing Customer'), ('partner', 'Partner'), ('public relations', 'Public Relations'), ('compaign', 'Campaign'), ('other', 'Other')], max_length=255, null=True, verbose_name='Source of Lead'), + ), + migrations.CreateModel( + name='Organization', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, max_length=100, null=True)), + ('org', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.org')), + ], + ), + migrations.AddField( + model_name='lead', + name='organization', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='lead_company', to='leads.organization'), + ), + ] diff --git a/leads/migrations/0019_auto_20211022_1732.py b/leads/migrations/0019_auto_20211022_1732.py new file mode 100644 index 0000000..8c54a9e --- /dev/null +++ b/leads/migrations/0019_auto_20211022_1732.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.8 on 2021-10-22 12:02 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0037_alter_profile_org'), + ('leads', '0018_auto_20211022_1731'), + ] + + operations = [ + migrations.RenameModel( + old_name='Organization', + new_name='Company', + ), + migrations.RenameField( + model_name='lead', + old_name='organization', + new_name='company', + ), + ] diff --git a/leads/models.py b/leads/models.py index 49bcbeb..ac8420b 100644 --- a/leads/models.py +++ b/leads/models.py @@ -1,5 +1,4 @@ import arrow -from django.core.cache import cache from django.db import models from django.utils.translation import pgettext_lazy from django.utils.translation import ugettext_lazy as _ @@ -7,11 +6,18 @@ from accounts.models import Tags from common.models import Org, Profile -from common.utils import COUNTRIES, LEAD_SOURCE, LEAD_STATUS, return_complete_address +from common.utils import COUNTRIES, LEAD_SOURCE, LEAD_STATUS, return_complete_address, INDCHOICES from contacts.models import Contact from teams.models import Teams +class Company(models.Model): + name = models.CharField(max_length=100, blank=True, null=True) + org = models.ForeignKey( + Org, on_delete=models.SET_NULL, null=True, blank=True + ) + + class Lead(models.Model): title = models.CharField( pgettext_lazy("Treatment Pronouns for the customer", "Title"), max_length=64 @@ -24,7 +30,7 @@ class Lead(models.Model): _("Status of Lead"), max_length=255, blank=True, null=True, choices=LEAD_STATUS ) source = models.CharField( - _("Source of Lead"), max_length=255, blank=True, null=True + _("Source of Lead"), max_length=255, blank=True, null=True, choices=LEAD_SOURCE ) address_line = models.CharField(_("Address"), max_length=255, blank=True, null=True) street = models.CharField(_("Street"), max_length=55, blank=True, null=True) @@ -54,6 +60,13 @@ class Lead(models.Model): org = models.ForeignKey( Org, on_delete=models.SET_NULL, null=True, blank=True, related_name="lead_org" ) + company = models.ForeignKey( + Company, on_delete=models.SET_NULL, null=True, blank=True, related_name="lead_company" + ) + skype_ID = models.CharField(max_length=100, null=True, blank=True) + industry = models.CharField( + _("Industry Type"), max_length=255, choices=INDCHOICES, blank=True, null=True + ) class Meta: diff --git a/leads/serializer.py b/leads/serializer.py index f4aa0e4..c5cd0ec 100644 --- a/leads/serializer.py +++ b/leads/serializer.py @@ -1,12 +1,11 @@ from rest_framework import serializers -from leads.models import Lead +from leads.models import Lead, Company from accounts.models import Tags, Account from common.serializer import ( ProfileSerializer, AttachmentsSerializer, LeadCommentSerializer, ) -from contacts.serializer import ContactSerializer from teams.serializer import TeamsSerializer @@ -16,6 +15,12 @@ class Meta: fields = ("id", "name", "slug") +class CompanySerializer(serializers.ModelSerializer): + class Meta: + model = Company + fields = ("id", "name") + + class LeadSerializer(serializers.ModelSerializer): assigned_to = ProfileSerializer(read_only=True, many=True) created_by = ProfileSerializer() @@ -60,13 +65,16 @@ class Meta: "tags", "created_from_site", "teams", + "skype_ID", + "industry", + "company" ) class LeadCreateSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): request_obj = kwargs.pop("request_obj", None) - super(LeadCreateSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.initial_data.get("status") == "converted": self.fields["account_name"].required = True self.fields["email"].required = True @@ -78,7 +86,8 @@ def __init__(self, *args, **kwargs): if self.instance: if self.instance.created_from_site: prev_choices = self.fields["source"]._get_choices() - prev_choices = prev_choices + [("micropyramid", "Micropyramid")] + prev_choices = prev_choices + \ + [("micropyramid", "Micropyramid")] self.fields["source"]._set_choices(prev_choices) def validate_account_name(self, account_name): @@ -114,10 +123,12 @@ def validate_title(self, title): .exclude(id=self.instance.id) .exists() ): - raise serializers.ValidationError("Lead already exists with this title") + raise serializers.ValidationError( + "Lead already exists with this title") else: if Lead.objects.filter(title__iexact=title, org=self.org).exists(): - raise serializers.ValidationError("Lead already exists with this title") + raise serializers.ValidationError( + "Lead already exists with this title") return title class Meta: @@ -139,5 +150,8 @@ class Meta: "state", "postcode", "country", - "org" + "org", + "skype_ID", + "industry", + "company" ) diff --git a/leads/swagger_params.py b/leads/swagger_params.py index a2900ab..6017113 100644 --- a/leads/swagger_params.py +++ b/leads/swagger_params.py @@ -46,6 +46,7 @@ openapi.Parameter("description", openapi.IN_QUERY, type=openapi.TYPE_STRING), openapi.Parameter("teams", openapi.IN_QUERY, type=openapi.TYPE_STRING), openapi.Parameter("assigned_to", openapi.IN_QUERY, type=openapi.TYPE_STRING), + openapi.Parameter("contacts", openapi.IN_QUERY, type=openapi.TYPE_STRING), openapi.Parameter("status", openapi.IN_QUERY, type=openapi.TYPE_STRING), openapi.Parameter("source", openapi.IN_QUERY, type=openapi.TYPE_STRING), openapi.Parameter("address_line", openapi.IN_QUERY, type=openapi.TYPE_STRING), @@ -55,6 +56,9 @@ openapi.Parameter("postcode", openapi.IN_QUERY, type=openapi.TYPE_STRING), openapi.Parameter("country", openapi.IN_QUERY, type=openapi.TYPE_STRING), openapi.Parameter("tags", openapi.IN_QUERY, type=openapi.TYPE_STRING), + openapi.Parameter("company", openapi.IN_QUERY, type=openapi.TYPE_STRING), + openapi.Parameter("industry", openapi.IN_QUERY, type=openapi.TYPE_STRING), + openapi.Parameter("skype_ID", openapi.IN_QUERY, type=openapi.TYPE_STRING), ] lead_upload_post_params = [ diff --git a/leads/tasks.py b/leads/tasks.py index 348108d..3b20b24 100644 --- a/leads/tasks.py +++ b/leads/tasks.py @@ -5,10 +5,9 @@ from django.core.cache import cache from django.core.mail import EmailMessage, EmailMultiAlternatives from django.db.models import Q -from django.shortcuts import reverse from django.template.loader import render_to_string -from common.models import User +from common.models import Profile, Org from leads.models import Lead @@ -67,8 +66,8 @@ def send_lead_assigned_emails(lead_id, new_assigned_to_list, site_address): "lead_detail_url": url, } mail_kwargs = {"subject": subject, "from_email": from_email} - for profile_id in users: - if user.email: + for profile in users: + if profile.user.email: context["user"] = profile.user html_content = get_rendered_html(template_name, context) mail_kwargs["html_content"] = html_content @@ -78,19 +77,19 @@ def send_lead_assigned_emails(lead_id, new_assigned_to_list, site_address): @app.task def send_email_to_assigned_user( - recipients, lead_id, domain="demo.django-crm.io", protocol="http", source="" + recipients, lead_id, source="" ): """ Send Mail To Users When they are assigned to a lead """ lead = Lead.objects.get(id=lead_id) created_by = lead.created_by for user in recipients: recipients_list = [] - user = User.objects.filter(id=user, is_active=True).first() - if user: - recipients_list.append(user.email) + profile = Profile.objects.filter(id=user, is_active=True).first() + if profile: + recipients_list.append(profile.user.email) context = {} - context["url"] = protocol + "://" + domain - context["user"] = user + context["url"] = settings.DOMAIN_NAME + context["user"] = profile.user context["lead"] = lead context["created_by"] = created_by context["source"] = source @@ -109,7 +108,7 @@ def create_lead_from_file(validated_rows, invalid_rows, user_id, source, company This function is used to create leads from a given file. """ email_regex = "^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,4})$" - user = User.objects.get(id=user_id) + profile = Profile.objects.get(id=user_id) org = Org.objects.filter(id=company_id).first() for row in validated_rows: if not Lead.objects.filter(title=row.get("title")).exists(): @@ -131,7 +130,7 @@ def create_lead_from_file(validated_rows, invalid_rows, user_id, source, company lead.status = row.get("status", "") lead.account_name = row.get("account_name", "")[:255] lead.created_from_site = False - lead.created_by = user + lead.created_by = profile lead.org = org lead.save() except Exception as e: diff --git a/leads/views.py b/leads/views.py index 7b24549..32efd1a 100644 --- a/leads/views.py +++ b/leads/views.py @@ -1,13 +1,10 @@ -from django.contrib.sites.shortcuts import get_current_site -from django.core.exceptions import PermissionDenied from django.db.models import Q from django.shortcuts import get_object_or_404 from accounts.models import Account, Tags -from accounts.tasks import send_email_to_assigned_user from contacts.models import Contact from leads import swagger_params -from common.models import User, Attachments, Comment, APISettings, Profile -from common.utils import COUNTRIES, LEAD_SOURCE, LEAD_STATUS +from common.models import Attachments, Comment, APISettings, Profile +from common.utils import COUNTRIES, LEAD_SOURCE, LEAD_STATUS, INDCHOICES from common.custom_auth import JSONWebTokenAuthentication from common.serializer import ( ProfileSerializer, @@ -15,14 +12,13 @@ AttachmentsSerializer, LeadCommentSerializer, ) -from leads.models import Lead +from leads.models import Lead, Company from leads.forms import LeadListForm -from leads.serializer import LeadSerializer, LeadCreateSerializer, TagsSerializer +from leads.serializer import LeadSerializer, LeadCreateSerializer, CompanySerializer from leads.tasks import ( create_lead_from_file, send_email_to_assigned_user, send_lead_assigned_emails, - update_leads_cache, ) from teams.serializer import TeamsSerializer from teams.models import Teams @@ -31,10 +27,8 @@ from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from rest_framework.pagination import LimitOffsetPagination -from rest_framework.decorators import api_view from drf_yasg.utils import swagger_auto_schema import json -from django.conf import settings class LeadListView(APIView, LimitOffsetPagination): @@ -56,109 +50,86 @@ def get_context_data(self, **kwargs): "tags", "assigned_to", ) - ) + ).order_by('-id') if self.request.profile.role != "ADMIN" and not self.request.user.is_superuser: queryset = queryset.filter( Q(assigned_to__in=[self.request.profile]) | Q( created_by=self.request.profile) ) - request_post = params - if request_post: - if request_post.get("name"): + if params: + if params.get("name"): queryset = queryset.filter( - Q(first_name__icontains=request_post.get("name")) - & Q(last_name__icontains=request_post.get("name")) + Q(first_name__icontains=params.get("name")) + & Q(last_name__icontains=params.get("name")) ) - if request_post.get("title"): + if params.get("title"): queryset = queryset.filter( - title__icontains=request_post.get("title")) - if request_post.get("source"): - queryset = queryset.filter(source=request_post.get("source")) - if request_post.getlist("assigned_to"): + title__icontains=params.get("title")) + if params.get("source"): + queryset = queryset.filter(source=params.get("source")) + if params.getlist("assigned_to"): queryset = queryset.filter( assigned_to__id__in=json.loads( - request_post.get("assigned_to")) + params.get("assigned_to")) ) - if request_post.get("status"): - queryset = queryset.filter(status=request_post.get("status")) - if request_post.get("tags"): + if params.get("status"): + queryset = queryset.filter(status=params.get("status")) + if params.get("tags"): queryset = queryset.filter( - tags__in=json.loads(request_post.get("tags")) + tags__in=json.loads(params.get("tags")) ) - if request_post.get("city"): + if params.get("city"): queryset = queryset.filter( - city__icontains=request_post.get("city")) - if request_post.get("email"): + city__icontains=params.get("city")) + if params.get("email"): queryset = queryset.filter( - email__icontains=request_post.get("email")) + email__icontains=params.get("email")) context = {} - search = False - if ( - params.get("title") - or params.get("source") - or params.get("assigned_to") - or params.get("status") - or params.get("tags") - ): - search = True - context["search"] = search - queryset_open = queryset.exclude(status="closed").order_by("id") + queryset_open = queryset.exclude(status="closed") results_leads_open = self.paginate_queryset( queryset_open.distinct(), self.request, view=self ) open_leads = LeadSerializer(results_leads_open, many=True).data + if results_leads_open: + offset = queryset_open.filter( + id__gte=results_leads_open[-1].id).count() + if offset == queryset_open.count(): + offset = None + else: + offset = 0 context["per_page"] = 10 context["open_leads"] = { "leads_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, "open_leads": open_leads, + "offset": offset } - queryset_close = queryset.filter(status="closed").order_by("id") + queryset_close = queryset.filter(status="closed") results_leads_close = self.paginate_queryset( queryset_close.distinct(), self.request, view=self ) close_leads = LeadSerializer(results_leads_close, many=True).data + if results_leads_close: + offset = queryset_close.filter( + id__gte=results_leads_close[-1].id).count() + if offset == queryset_close.count(): + offset = None + else: + offset = 0 context["close_leads"] = { "leads_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, "close_leads": close_leads, + "offset": offset } context["status"] = LEAD_STATUS context["source"] = LEAD_SOURCE - users = [] - if self.request.profile.role == "ADMIN" or self.request.user.is_superuser: - users = Profile.objects.filter( - is_active=True, org=self.request.org - ).order_by("user__email") - elif self.request.profile.google.all(): - users = [] - else: - users = Profile.objects.filter( - role="ADMIN", org=self.request.org - ).order_by("user__email") - context["users"] = ProfileSerializer(users, many=True).data - tag_ids = list( - set( - queryset.values_list( - "tags", - flat=True, - ) - ) - ) - - context["tags"] = TagsSerializer( - Tags.objects.filter(id__in=tag_ids), many=True - ).data - + context["companies"] = CompanySerializer( + Company.objects.filter(org=self.request.org), many=True).data context["countries"] = COUNTRIES + context["industries"] = INDCHOICES return context @swagger_auto_schema( @@ -177,16 +148,12 @@ def post(self, request, *args, **kwargs): if len(self.request.data) == 0 else self.request.data ) - data = {} serializer = LeadCreateSerializer(data=params, request_obj=request) if serializer.is_valid(): lead_obj = serializer.save( created_by=request.profile, org=request.org) if params.get("tags"): tags = json.loads(params.get("tags")) - # for t in tags: - # tag,_ = Tags.objects.get_or_create(name=t) - # lead_obj.tags.add(tag) for t in tags: tag = Tags.objects.filter(slug=t.lower()) if tag.exists(): @@ -195,14 +162,16 @@ def post(self, request, *args, **kwargs): tag = Tags.objects.create(name=t) lead_obj.tags.add(tag) + if params.get("contacts"): + obj_contact = Contact.objects.filter( + id=params.get("contacts"), org=request.org) + lead_obj.contacts.add(obj_contact) + recipients = list( lead_obj.assigned_to.all().values_list("id", flat=True)) - current_site = get_current_site(self.request) send_email_to_assigned_user.delay( recipients, lead_obj.id, - domain=current_site.domain, - protocol=request.scheme, ) if request.FILES.get("lead_attachment"): @@ -214,36 +183,19 @@ def post(self, request, *args, **kwargs): attachment.attachment = request.FILES.get("lead_attachment") attachment.save() - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter( - id=team, org=request.org) - if teams_ids.exists(): - lead_obj.teams.add(team) - else: - lead_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if params.get("assigned_to"): - assinged_to_users_ids = json.loads( - params.get("assigned_to")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter( - id=user_id, org=request.org) - if user.exists(): - lead_obj.assigned_to.add(user_id) - else: - lead_obj.delete() - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + lead_obj.teams.add(*teams) + + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org) + lead_obj.assigned_to.add(*profiles) + if params.get("status") == "converted": account_object = Account.objects.create( created_by=request.profile, @@ -275,12 +227,9 @@ def post(self, request, *args, **kwargs): assigned_to_list = json.loads( params.getlist("assigned_to")) recipients = assigned_to_list - current_site = get_current_site(self.request) send_email_to_assigned_user.delay( recipients, lead_obj.id, - domain=current_site.domain, - protocol=request.scheme, ) return Response( { @@ -477,7 +426,6 @@ def put(self, request, pk, **kwargs): if len(self.request.data) == 0 else self.request.data ) - data = {} self.lead_obj = self.get_object(pk) if self.lead_obj.org != request.org: return Response( @@ -513,12 +461,9 @@ def put(self, request, pk, **kwargs): ) recipients = list(set(assigned_to_list) - set(previous_assigned_to_users)) - current_site = get_current_site(self.request) send_email_to_assigned_user.delay( recipients, lead_obj.id, - domain=current_site.domain, - protocol=request.scheme, ) if request.FILES.get("lead_attachment"): attachment = Attachments() @@ -529,41 +474,26 @@ def put(self, request, pk, **kwargs): attachment.attachment = request.FILES.get("lead_attachment") attachment.save() - if self.request.profile.role == "ADMIN": - lead_obj.teams.clear() - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter(id=team, org=request.org) - if teams_ids.exists(): - lead_obj.teams.add(team) - else: - lead_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - else: - lead_obj.teams.clear() - - lead_obj.assigned_to.clear() - if params.get("assigned_to"): - assinged_to_users_ids = json.loads( - params.get("assigned_to")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter(id=user_id, org=request.org) - if user.exists(): - lead_obj.assigned_to.add(user_id) - else: - lead_obj.delete() - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - else: - lead_obj.assigned_to.clear() + lead_obj.contacts.clear() + if params.get("contacts"): + obj_contact = Contact.objects.filter( + id=params.get("contacts"), org=request.org) + lead_obj.contacts.add(obj_contact) + + lead_obj.teams.clear() + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + lead_obj.teams.add(*teams) + + lead_obj.assigned_to.clear() + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org) + lead_obj.assigned_to.add(*profiles) if params.get("status") == "converted": account_object = Account.objects.create( @@ -596,12 +526,9 @@ def put(self, request, pk, **kwargs): # account_object.assigned_to.add(*params.getlist('assigned_to')) assigned_to_list = json.loads(params.get("assigned_to")) recipients = assigned_to_list - current_site = get_current_site(self.request) send_email_to_assigned_user.delay( recipients, lead_obj.id, - domain=current_site.domain, - protocol=request.scheme, ) for comment in lead_obj.leads_comments.all(): @@ -654,25 +581,23 @@ class LeadUploadView(APIView): tags=["Leads"], manual_parameters=swagger_params.lead_upload_post_params ) def post(self, request, *args, **kwargs): - if request.method == "POST": - lead_form = LeadListForm(request.POST, request.FILES) - if lead_form.is_valid(): - create_lead_from_file.delay( - lead_form.validated_rows, - lead_form.invalid_rows, - request.profile.id, - request.get_host(), - request.org.id - ) - return Response( - {"error": False, "message": "Leads created Successfully"}, - status=status.HTTP_200_OK, - ) - else: - return Response( - {"error": True, "errors": lead_form.errors}, - status=status.HTTP_400_BAD_REQUEST, - ) + lead_form = LeadListForm(request.POST, request.FILES) + if lead_form.is_valid(): + create_lead_from_file.delay( + lead_form.validated_rows, + lead_form.invalid_rows, + request.profile.id, + request.get_host(), + request.org.id + ) + return Response( + {"error": False, "message": "Leads created Successfully"}, + status=status.HTTP_200_OK, + ) + return Response( + {"error": True, "errors": lead_form.errors}, + status=status.HTTP_400_BAD_REQUEST, + ) class LeadCommentView(APIView): @@ -696,25 +621,23 @@ def put(self, request, pk, format=None): or request.profile == obj.commented_by ): serializer = LeadCommentSerializer(obj, data=params) - if params.get("comment"): - if serializer.is_valid(): - serializer.save() - return Response( - {"error": False, "message": "Comment Submitted"}, - status=status.HTTP_200_OK, - ) + if serializer.is_valid(): + serializer.save() return Response( - {"error": True, "errors": serializer.errors}, - status=status.HTTP_400_BAD_REQUEST, + {"error": False, "message": "Comment Submitted"}, + status=status.HTTP_200_OK, ) - else: return Response( - { - "error": True, - "errors": "You don't have permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, + {"error": True, "errors": serializer.errors}, + status=status.HTTP_400_BAD_REQUEST, ) + return Response( + { + "error": True, + "errors": "You don't have permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) @swagger_auto_schema( tags=["Leads"], manual_parameters=swagger_params.organization_params @@ -731,14 +654,14 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Comment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You do not have permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + + return Response( + { + "error": True, + "errors": "You do not have permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) class LeadAttachmentView(APIView): @@ -761,14 +684,13 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Attachment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) class CreateLeadFromSite(APIView): diff --git a/opportunity/serializer.py b/opportunity/serializer.py index f9905b9..d5d592a 100644 --- a/opportunity/serializer.py +++ b/opportunity/serializer.py @@ -58,9 +58,8 @@ class OpportunityCreateSerializer(serializers.ModelSerializer): closed_on = serializers.DateField def __init__(self, *args, **kwargs): - opportunity_view = kwargs.pop("opportunity", False) request_obj = kwargs.pop("request_obj", None) - super(OpportunityCreateSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.org = request_obj.org def validate_name(self, name): diff --git a/opportunity/tasks.py b/opportunity/tasks.py index 43384f4..f244feb 100644 --- a/opportunity/tasks.py +++ b/opportunity/tasks.py @@ -1,11 +1,8 @@ from celery import Celery from django.conf import settings -from django.core.mail import EmailMultiAlternatives, EmailMessage -from django.db.models import Q -from django.shortcuts import reverse +from django.core.mail import EmailMessage from django.template.loader import render_to_string - -from common.models import User +from common.models import Profile from opportunity.models import Opportunity app = Celery("redis://") @@ -13,7 +10,7 @@ @app.task def send_email_to_assigned_user( - recipients, opportunity_id, domain="demo.django-crm.io", protocol="http" + recipients, opportunity_id ): """ Send Mail To Users When they are assigned to a opportunity """ opportunity = Opportunity.objects.get(id=opportunity_id) @@ -24,7 +21,7 @@ def send_email_to_assigned_user( if profile: recipients_list.append(profile.user.email) context = {} - context["url"] = protocol + "://" + domain + context["url"] = settings.DOMAIN_NAME context["user"] = profile.user context["opportunity"] = opportunity context["created_by"] = created_by diff --git a/opportunity/views.py b/opportunity/views.py index c7ae172..d0d3bb7 100644 --- a/opportunity/views.py +++ b/opportunity/views.py @@ -1,24 +1,19 @@ -import pytz -from django.conf import settings -from django.contrib.sites.shortcuts import get_current_site from django.db.models import Q from opportunity.models import Opportunity from opportunity.tasks import send_email_to_assigned_user from opportunity import swagger_params from opportunity.serializer import ( OpportunitySerializer, - TagsSerializer, OpportunityCreateSerializer, ) from accounts.models import Account, Tags from accounts.serializer import AccountSerializer -from common.models import User, Attachments, Comment, Profile +from common.models import Attachments, Comment, Profile from common.custom_auth import JSONWebTokenAuthentication from common.serializer import ( ProfileSerializer, CommentSerializer, AttachmentsSerializer, - LeadCommentSerializer, ) from common.utils import ( STAGES, @@ -26,11 +21,7 @@ CURRENCY_CODES, ) from contacts.models import Contact -from leads.models import Lead -from opportunity.models import SOURCES, STAGES, Opportunity from contacts.serializer import ContactSerializer -from teams.serializer import TeamsSerializer -from opportunity.serializer import OpportunitySerializer from teams.models import Teams from rest_framework import status @@ -54,75 +45,62 @@ def get_context_data(self, **kwargs): if len(self.request.data) == 0 else self.request.data ) - queryset = self.model.objects.filter(org=self.request.org) + queryset = self.model.objects.filter( + org=self.request.org).order_by('-id') accounts = Account.objects.filter(org=self.request.org) contacts = Contact.objects.filter(org=self.request.org) if self.request.profile.role != "ADMIN" and not self.request.user.is_superuser: queryset = queryset.filter( - Q(created_by=self.request.profile) | Q(assigned_to=self.request.profile) + Q(created_by=self.request.profile) | Q( + assigned_to=self.request.profile) ).distinct() accounts = accounts.filter( - Q(created_by=self.request.profile) | Q(assigned_to=self.request.profile) + Q(created_by=self.request.profile) | Q( + assigned_to=self.request.profile) ).distinct() contacts = contacts.filter( - Q(created_by=self.request.profile) | Q(assigned_to=self.request.profile) + Q(created_by=self.request.profile) | Q( + assigned_to=self.request.profile) ).distinct() if params: - request_post = params - if request_post.get("name"): - queryset = queryset.filter(name__icontains=request_post.get("name")) - if request_post.get("account"): - queryset = queryset.filter(account=request_post.get("account")) - if request_post.get("stage"): - queryset = queryset.filter(stage__contains=request_post.get("stage")) - if request_post.get("lead_source"): + if params.get("name"): + queryset = queryset.filter(name__icontains=params.get("name")) + if params.get("account"): + queryset = queryset.filter(account=params.get("account")) + if params.get("stage"): + queryset = queryset.filter(stage__contains=params.get("stage")) + if params.get("lead_source"): queryset = queryset.filter( - lead_source__contains=request_post.get("lead_source") + lead_source__contains=params.get("lead_source") ) - if request_post.get("tags"): + if params.get("tags"): queryset = queryset.filter( - tags__in=json.loads(request_post.get("tags")) + tags__in=json.loads(params.get("tags")) ).distinct() context = {} - search = False - if ( - params.get("name") - or params.get("account") - or params.get("stage") - or params.get("lead_source") - or params.get("tags") - ): - search = True - context["search"] = search - results_opportunities = self.paginate_queryset( queryset.distinct(), self.request, view=self ) - opportunities = OpportunitySerializer(results_opportunities, many=True).data - context["per_page"] = 10 + opportunities = OpportunitySerializer( + results_opportunities, many=True).data + if results_opportunities: + offset = queryset.filter( + id__gte=results_opportunities[-1].id).count() + if offset == queryset.count(): + offset = None + else: + offset = 0 context.update( { "opportunities_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, + "offset": offset, } ) context["opportunities"] = opportunities - context["users"] = ProfileSerializer( - Profile.objects.filter(is_active=True, org=self.request.org).order_by("user__email"), - many=True, - ).data - tag_ids = list(set(Opportunity.objects.filter(org=self.request.org).values_list("tags", flat=True))) - context["tags"] = TagsSerializer( - Tags.objects.filter(id__in=tag_ids), many=True - ).data context["accounts_list"] = AccountSerializer(accounts, many=True).data context["contacts_list"] = ContactSerializer(contacts, many=True).data - if self.request.profile == "ADMIN": - context["teams_list"] = TeamsSerializer(Teams.objects.filter(org=self.request.org), many=True).data context["stage"] = STAGES context["lead_source"] = SOURCES context["currency"] = CURRENCY_CODES @@ -142,9 +120,10 @@ def get(self, request, *args, **kwargs): manual_parameters=swagger_params.opportunity_create_post_params, ) def post(self, request, *args, **kwargs): - params = request.query_params if len(request.data) == 0 else request.data - data = {} - serializer = OpportunityCreateSerializer(data=params, request_obj=request) + params = request.query_params if len( + request.data) == 0 else request.data + serializer = OpportunityCreateSerializer( + data=params, request_obj=request) if serializer.is_valid(): opportunity_obj = serializer.save( created_by=request.profile, @@ -153,18 +132,12 @@ def post(self, request, *args, **kwargs): ) if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter(id=contact, org=request.org) - if obj_contact.exists(): - opportunity_obj.contacts.add(contact) - else: - opportunity_obj.delete() - data["contacts"] = "Please enter valid contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + contacts_list = json.loads(params.get("contacts")) + contacts = Contact.objects.filter( + id__in=contacts_list, org=request.org + ) + opportunity_obj.contacts.add(*contacts) + if params.get("tags"): tags = json.loads(params.get("tags")) for tag in tags: @@ -180,34 +153,18 @@ def post(self, request, *args, **kwargs): if stage in ["CLOSED WON", "CLOSED LOST"]: opportunity_obj.closed_by = self.request.profile - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - obj_team = Teams.objects.filter(id=team, org=request.org) - if obj_team.exists(): - opportunity_obj.teams.add(team) - else: - opportunity_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if params.get("assigned_to"): - assinged_to_users_ids = json.loads(params.get("assigned_to")) - - for user_id in assinged_to_users_ids: - profile = Profile.objects.filter(id=user_id, org=request.org) - if profile.exists(): - opportunity_obj.assigned_to.add(user_id) - else: - opportunity_obj.delete() - data["assigned_to"] = "Please enter valid user" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + opportunity_obj.teams.add(*teams) + + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org, is_active=True) + opportunity_obj.assigned_to.add(*profiles) if self.request.FILES.get("opportunity_attachment"): attachment = Attachments() @@ -216,20 +173,17 @@ def post(self, request, *args, **kwargs): "opportunity_attachment" ).name attachment.opportunity = opportunity_obj - attachment.attachment = self.request.FILES.get("opportunity_attachment") + attachment.attachment = self.request.FILES.get( + "opportunity_attachment") attachment.save() - assigned_to_list = list( + recipients = list( opportunity_obj.assigned_to.all().values_list("id", flat=True) ) - recipients = assigned_to_list - current_site = get_current_site(self.request) send_email_to_assigned_user.delay( recipients, opportunity_obj.id, - domain=current_site.domain, - protocol=self.request.scheme, ) return Response( {"error": False, "message": "Opportunity Created Successfully"}, @@ -255,9 +209,9 @@ def get_object(self, pk): manual_parameters=swagger_params.opportunity_create_post_params, ) def put(self, request, pk, format=None): - params = request.query_params if len(request.data) == 0 else request.data + params = request.query_params if len( + request.data) == 0 else request.data opportunity_object = self.get_object(pk=pk) - data = {} if opportunity_object.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, @@ -284,23 +238,19 @@ def put(self, request, pk, format=None): ) if serializer.is_valid(): - opportunity_object = serializer.save(closed_on=params.get("due_date")) + opportunity_object = serializer.save( + closed_on=params.get("due_date")) previous_assigned_to_users = list( opportunity_object.assigned_to.all().values_list("id", flat=True) ) opportunity_object.contacts.clear() if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter(id=contact, org=request.org) - if obj_contact.exists(): - opportunity_object.contacts.add(contact) - else: - data["contacts"] = "Please enter valid Contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + contacts_list = json.loads(params.get("contacts")) + contacts = Contact.objects.filter( + id__in=contacts_list, org=request.org + ) + opportunity_object.contacts.add(*contacts) + opportunity_object.tags.clear() if params.get("tags"): tags = json.loads(params.get("tags")) @@ -315,36 +265,22 @@ def put(self, request, pk, format=None): if params.get("stage"): stage = params.get("stage") if stage in ["CLOSED WON", "CLOSED LOST"]: - opportunity_object.closed_by_id = self.request.profile.id - - if self.request.profile.role == "ADMIN": - opportunity_object.teams.clear() - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - obj_team = Teams.objects.filter(id=team, org=request.org) - if obj_team.exists(): - opportunity_object.teams.add(team) - else: - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - - opportunity_object.assigned_to.clear() - if params.get("assigned_to"): - assinged_to_users_ids = json.loads(params.get("assigned_to")) - for user_id in assinged_to_users_ids: - profile = Profile.objects.filter(id=user_id, org=request.org) - if profile.exists(): - opportunity_object.assigned_to.add(user_id) - else: - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + opportunity_object.closed_by = self.request.profile + + opportunity_object.teams.clear() + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + opportunity_object.teams.add(*teams) + + opportunity_object.assigned_to.clear() + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org, is_active=True) + opportunity_object.assigned_to.add(*profiles) if self.request.FILES.get("opportunity_attachment"): attachment = Attachments() @@ -353,19 +289,18 @@ def put(self, request, pk, format=None): "opportunity_attachment" ).name attachment.opportunity = opportunity_object - attachment.attachment = self.request.FILES.get("opportunity_attachment") + attachment.attachment = self.request.FILES.get( + "opportunity_attachment") attachment.save() assigned_to_list = list( opportunity_object.assigned_to.all().values_list("id", flat=True) ) - recipients = list(set(assigned_to_list) - set(previous_assigned_to_users)) - current_site = get_current_site(self.request) + recipients = list(set(assigned_to_list) - + set(previous_assigned_to_users)) send_email_to_assigned_user.delay( recipients, opportunity_object.id, - domain=current_site.domain, - protocol=self.request.scheme, ) return Response( {"error": False, "message": "Opportunity Updated Successfully"}, @@ -407,7 +342,8 @@ def delete(self, request, pk, format=None): def get(self, request, pk, format=None): self.opportunity = self.get_object(pk=pk) context = {} - context["opportunity_obj"] = OpportunitySerializer(self.opportunity).data + context["opportunity_obj"] = OpportunitySerializer( + self.opportunity).data if self.opportunity.org != request.org: return Response( {"error": True, "errors": "User company doesnot match with header...."}, @@ -426,15 +362,14 @@ def get(self, request, pk, format=None): status=status.HTTP_403_FORBIDDEN, ) - comment_permission = ( - True - if ( - self.request.profile == self.opportunity.created_by - or self.request.user.is_superuser - or self.request.profile.role == "ADMIN" - ) - else False - ) + comment_permission = False + + if ( + self.request.profile == self.opportunity.created_by + or self.request.user.is_superuser + or self.request.profile.role == "ADMIN" + ): + comment_permission = True if self.request.user.is_superuser or self.request.profile.role == "ADMIN": users_mention = list( @@ -444,7 +379,8 @@ def get(self, request, pk, format=None): ) elif self.request.profile != self.opportunity.created_by: if self.opportunity.created_by: - users_mention = [{"username": self.opportunity.created_by.user.username}] + users_mention = [ + {"username": self.opportunity.created_by.user.username}] else: users_mention = [] else: @@ -520,7 +456,8 @@ def post(self, request, pk, **kwargs): "opportunity_attachment" ).name attachment.opportunity = self.opportunity_obj - attachment.attachment = self.request.FILES.get("opportunity_attachment") + attachment.attachment = self.request.FILES.get( + "opportunity_attachment") attachment.save() comments = Comment.objects.filter(opportunity=self.opportunity_obj).order_by( @@ -552,7 +489,8 @@ def get_object(self, pk): manual_parameters=swagger_params.opportunity_comment_edit_params, ) def put(self, request, pk, format=None): - params = request.query_params if len(request.data) == 0 else request.data + params = request.query_params if len( + request.data) == 0 else request.data obj = self.get_object(pk) if ( request.profile.role == "ADMIN" @@ -571,14 +509,13 @@ def put(self, request, pk, format=None): {"error": True, "errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to perform this action.", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to perform this action.", + }, + status=status.HTTP_403_FORBIDDEN, + ) @swagger_auto_schema( tags=["Opportunities"], manual_parameters=swagger_params.organization_params @@ -595,14 +532,13 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Comment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You do not have permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You do not have permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) class OpportunityAttachmentView(APIView): @@ -625,11 +561,10 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Attachment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have permission to perform this action.", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have permission to perform this action.", + }, + status=status.HTTP_403_FORBIDDEN, + ) diff --git a/tasks/serializer.py b/tasks/serializer.py index 841f649..9d3be00 100644 --- a/tasks/serializer.py +++ b/tasks/serializer.py @@ -39,20 +39,21 @@ class Meta: class TaskCreateSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): request_obj = kwargs.pop("request_obj", None) - super(TaskCreateSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) + self.org = request_obj.org self.fields["title"].required = True def validate_title(self, title): if self.instance: if ( - Task.objects.filter(title__iexact=title) + Task.objects.filter(title__iexact=title, org=self.org) .exclude(id=self.instance.id) .exists() ): raise serializers.ValidationError("Task already exists with this title") else: - if Task.objects.filter(title__iexact=title).exists(): + if Task.objects.filter(title__iexact=title, org=self.org).exists(): raise serializers.ValidationError("Task already exists with this title") return title diff --git a/tasks/views.py b/tasks/views.py index 94f0120..8329a3b 100644 --- a/tasks/views.py +++ b/tasks/views.py @@ -1,5 +1,3 @@ -from django.contrib.sites.shortcuts import get_current_site -from django.core.exceptions import PermissionDenied from django.db.models import Q from accounts.models import Account from accounts.serializer import AccountSerializer @@ -12,7 +10,6 @@ ProfileSerializer, CommentSerializer, AttachmentsSerializer, - CommentSerializer, ) from tasks import swagger_params from tasks.models import Task @@ -40,64 +37,53 @@ def get_context_data(self, **kwargs): if len(self.request.data) == 0 else self.request.data ) - queryset = self.model.objects.filter(org=self.request.org) + queryset = self.model.objects.filter( + org=self.request.org).order_by('-id') accounts = Account.objects.filter(org=self.request.org) contacts = Contact.objects.filter(org=self.request.org) if self.request.profile.role != "ADMIN" and not self.request.profile.is_admin: queryset = queryset.filter( - Q(assigned_to__in=[self.request.profile]) | Q(created_by=self.request.profile) + Q(assigned_to__in=[self.request.profile]) | Q( + created_by=self.request.profile) ) accounts = accounts.filter( - Q(created_by=self.request.profile) | Q(assigned_to=self.request.profile) + Q(created_by=self.request.profile) | Q( + assigned_to=self.request.profile) ).distinct() contacts = contacts.filter( - Q(created_by=self.request.profile) | Q(assigned_to=self.request.profile) + Q(created_by=self.request.profile) | Q( + assigned_to=self.request.profile) ).distinct() - request_post = params - if request_post: - if request_post.get("title"): - queryset = queryset.filter(title__icontains=request_post.get("title")) - if request_post.get("status"): - queryset = queryset.filter(status=request_post.get("status")) - if request_post.get("priority"): - queryset = queryset.filter(priority=request_post.get("priority")) + if params: + if params.get("title"): + queryset = queryset.filter( + title__icontains=params.get("title")) + if params.get("status"): + queryset = queryset.filter(status=params.get("status")) + if params.get("priority"): + queryset = queryset.filter( + priority=params.get("priority")) context = {} - search = False - if params.get("title") or params.get("status") or params.get("priority"): - search = True - context["search"] = search results_tasks = self.paginate_queryset( queryset.distinct(), self.request, view=self ) tasks = TaskSerializer(results_tasks, many=True).data - context["per_page"] = 10 + if results_tasks: + offset = queryset.filter(id__gte=results_tasks[-1].id).count() + if offset == queryset.count(): + offset = None + else: + offset = 0 context.update( { "tasks_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, + "offset": offset, } ) context["tasks"] = tasks context["status"] = STATUS_CHOICES context["priority"] = PRIORITY_CHOICES - users = [] - if self.request.profile.role == "ADMIN" or self.request.profile.is_admin: - users = Profile.objects.filter( - is_active=True, org=self.request.org - ).order_by("user__email") - elif self.request.profile.google.all(): - users = [] - else: - users = Profile.objects.filter( - role="ADMIN", org=self.request.org - ).order_by("user__email") - context["users"] = ProfileSerializer(users, many=True).data - if self.request.profile == "ADMIN": - context["teams_list"] = TeamsSerializer(Teams.objects.filter( - org=self.request.org), many=True).data context["accounts_list"] = AccountSerializer(accounts, many=True).data context["contacts_list"] = ContactSerializer(contacts, many=True).data return context @@ -118,7 +104,6 @@ def post(self, request, *args, **kwargs): if len(self.request.data) == 0 else self.request.data ) - data = {} serializer = TaskCreateSerializer(data=params, request_obj=request) if serializer.is_valid(): task_obj = serializer.save( @@ -127,47 +112,24 @@ def post(self, request, *args, **kwargs): org=request.org ) if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter( - id=contact, org=request.org - ) - if obj_contact.exists(): - task_obj.contacts.add(contact) - else: - task_obj.delete() - data["contacts"] = "Please enter valid contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if self.request.profile.role == "ADMIN": - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter(id=team, org=request.org) - if teams_ids.exists(): - task_obj.teams.add(team) - else: - task_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if params.get("assigned_to"): - assinged_to_users_ids = json.loads(params.get("assigned_to")) - for user_id in assinged_to_users_ids: - profile = Profile.objects.filter(id=user_id, org=request.org) - if profile.exists(): - task_obj.assigned_to.add(user_id) - else: - task_obj.delete() - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + contacts_list = json.loads(params.get("contacts")) + contacts = Contact.objects.filter( + id__in=contacts_list, org=request.org + ) + task_obj.contacts.add(*contacts) + + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + task_obj.teams.add(*teams) + + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org, is_active=True) + task_obj.assigned_to.add(*profiles) return Response( {"error": False, "message": "Task Created Successfully"}, @@ -205,7 +167,8 @@ def get_context_data(self, **kwargs): ) comments = Comment.objects.filter(task=self.task_obj).order_by("-id") - attachments = Attachments.objects.filter(task=self.task_obj).order_by("-id") + attachments = Attachments.objects.filter( + task=self.task_obj).order_by("-id") assigned_data = self.task_obj.assigned_to.values("id", "user__email") @@ -216,9 +179,11 @@ def get_context_data(self, **kwargs): ).values("user__username") ) elif self.request.profile != self.task_obj.created_by: - users_mention = [{"username": self.task_obj.created_by.user.username}] + users_mention = [ + {"username": self.task_obj.created_by.user.username}] else: - users_mention = list(self.task_obj.assigned_to.all().values("user__username")) + users_mention = list( + self.task_obj.assigned_to.all().values("user__username")) if self.request.profile.role == "ADMIN" or self.request.profile.is_admin: users = Profile.objects.filter( is_active=True, org=self.request.org @@ -242,7 +207,8 @@ def get_context_data(self, **kwargs): team_ids = [user.id for user in self.task_obj.get_team_users] all_user_ids = users.values_list("id", flat=True) users_excluding_team_id = set(all_user_ids) - set(team_ids) - users_excluding_team = Profile.objects.filter(id__in=users_excluding_team_id) + users_excluding_team = Profile.objects.filter( + id__in=users_excluding_team_id) context.update( { "task_obj": TaskSerializer(self.task_obj).data, @@ -301,12 +267,14 @@ def post(self, request, pk, **kwargs): if self.request.FILES.get("task_attachment"): attachment = Attachments() attachment.created_by = self.request.profile - attachment.file_name = self.request.FILES.get("task_attachment").name + attachment.file_name = self.request.FILES.get( + "task_attachment").name attachment.task = self.task_obj attachment.attachment = self.request.FILES.get("task_attachment") attachment.save() - comments = Comment.objects.filter(task__id=self.task_obj.id).order_by("-id") + comments = Comment.objects.filter( + task__id=self.task_obj.id).order_by("-id") attachments = Attachments.objects.filter(task__id=self.task_obj.id).order_by( "-id" ) @@ -328,7 +296,6 @@ def put(self, request, pk, **kwargs): if len(self.request.data) == 0 else self.request.data ) - data = {} self.task_obj = self.get_object(pk) serializer = TaskCreateSerializer( data=params, @@ -342,51 +309,27 @@ def put(self, request, pk, **kwargs): ) task_obj.contacts.clear() if params.get("contacts"): - contacts = json.loads(params.get("contacts")) - for contact in contacts: - obj_contact = Contact.objects.filter(id=contact) - if obj_contact.exists(): - task_obj.contacts.add(contact) - else: - data["contacts"] = "Please enter valid Contact" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - if self.request.profile.role == "ADMIN": - task_obj.teams.clear() - if params.get("teams"): - teams = json.loads(params.get("teams")) - for team in teams: - teams_ids = Teams.objects.filter(id=team) - if teams_ids.exists(): - task_obj.teams.add(team) - else: - task_obj.delete() - data["team"] = "Please enter valid Team" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - else: - task_obj.teams.clear() - - task_obj.assigned_to.clear() - if params.get("assigned_to"): - assinged_to_users_ids = json.loads(params.get("assigned_to")) - for user_id in assinged_to_users_ids: - profile = Profile.objects.filter(id=user_id, org=request.org) - if profile.exists(): - task_obj.assigned_to.add(user_id) - else: - task_obj.delete() - data["assigned_to"] = "Please enter valid User" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) - else: - task_obj.assigned_to.clear() + contacts_list = json.loads(params.get("contacts")) + contacts = Contact.objects.filter( + id__in=contacts_list, org=request.org + ) + task_obj.contacts.add(*contacts) + + task_obj.teams.clear() + if params.get("teams"): + teams_list = json.loads(params.get("teams")) + teams = Teams.objects.filter( + id__in=teams_list, org=request.org) + task_obj.teams.add(*teams) + + task_obj.assigned_to.clear() + if params.get("assigned_to"): + assinged_to_list = json.loads( + params.get("assigned_to")) + profiles = Profile.objects.filter( + id__in=assinged_to_list, org=request.org, is_active=True) + task_obj.assigned_to.add(*profiles) + return Response( {"error": False, "message": "Task updated Successfully"}, status=status.HTTP_200_OK, @@ -429,7 +372,8 @@ def get_object(self, pk): tags=["Tasks"], manual_parameters=swagger_params.task_comment_edit_params ) def put(self, request, pk, format=None): - params = request.query_params if len(request.data) == 0 else request.data + params = request.query_params if len( + request.data) == 0 else request.data obj = self.get_object(pk) if ( request.profile.role == "ADMIN" @@ -448,14 +392,14 @@ def put(self, request, pk, format=None): {"error": True, "errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) - else: - return Response( - { - "error": True, - "errors": "You don't have Permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + + return Response( + { + "error": True, + "errors": "You don't have Permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) @swagger_auto_schema( tags=["Tasks"], manual_parameters=swagger_params.organization_params @@ -472,14 +416,13 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Comment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have Permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have Permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) class TaskAttachmentView(APIView): @@ -502,11 +445,10 @@ def delete(self, request, pk, format=None): {"error": False, "message": "Attachment Deleted Successfully"}, status=status.HTTP_200_OK, ) - else: - return Response( - { - "error": True, - "errors": "You don't have Permission to perform this action", - }, - status=status.HTTP_403_FORBIDDEN, - ) + return Response( + { + "error": True, + "errors": "You don't have Permission to perform this action", + }, + status=status.HTTP_403_FORBIDDEN, + ) diff --git a/teams/models.py b/teams/models.py index f38ef1e..8260c53 100644 --- a/teams/models.py +++ b/teams/models.py @@ -1,7 +1,7 @@ import arrow from django.db import models -from common.models import User, Org, Profile +from common.models import Org, Profile from django.utils.translation import ugettext_lazy as _ diff --git a/teams/serializer.py b/teams/serializer.py index 9d50bf0..a7d1802 100644 --- a/teams/serializer.py +++ b/teams/serializer.py @@ -23,7 +23,7 @@ class Meta: class TeamCreateSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): request_obj = kwargs.pop("request_obj", None) - super(TeamCreateSerializer, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.org = request_obj.org self.fields["name"].required = True diff --git a/teams/tasks.py b/teams/tasks.py index bf31851..468cffe 100644 --- a/teams/tasks.py +++ b/teams/tasks.py @@ -1,12 +1,5 @@ -from accounts.models import Account -from cases.models import Case from celery import Celery -from common.models import Document, User -from contacts.models import Contact -from events.models import Event -from leads.models import Lead -from opportunity.models import Opportunity -from tasks.models import Task +from common.models import Profile from teams.models import Teams app = Celery("redis://") @@ -15,7 +8,7 @@ @app.task def remove_users(removed_users_list, team_id): removed_users_list = [i for i in removed_users_list if i.isdigit()] - users_list = User.objects.filter(id__in=removed_users_list) + users_list = Profile.objects.filter(id__in=removed_users_list) if users_list.exists(): team = Teams.objects.filter(id=team_id).first() if team: @@ -76,7 +69,6 @@ def remove_users(removed_users_list, team_id): @app.task def update_team_users(team_id): """ this function updates assigned_to field on all models when a team is updated """ - pass team = Teams.objects.filter(id=team_id).first() if team: teams_members = team.users.all() diff --git a/teams/views.py b/teams/views.py index fe7aa9d..397d56a 100644 --- a/teams/views.py +++ b/teams/views.py @@ -1,14 +1,9 @@ -from django.contrib.sites.shortcuts import get_current_site -from django.core.exceptions import PermissionDenied -from django.db.models import Q from teams import swagger_params from teams.models import Teams from teams.tasks import update_team_users, remove_users from teams.serializer import TeamsSerializer, TeamCreateSerializer from common.models import Profile from common.custom_auth import JSONWebTokenAuthentication -from common.serializer import ProfileSerializer - from rest_framework import status from rest_framework.views import APIView from rest_framework.response import Response @@ -29,50 +24,37 @@ def get_context_data(self, **kwargs): if len(self.request.data) == 0 else self.request.data ) - queryset = self.model.objects.filter(org=self.request.org) - - request_post = params - if request_post: - if request_post.get("team_name"): + queryset = self.model.objects.filter(org=self.request.org).order_by('-id') + if params: + if params.get("team_name"): queryset = queryset.filter( - name__icontains=request_post.get("team_name") + name__icontains=params.get("team_name") ) - if request_post.get("created_by"): - queryset = queryset.filter(created_by=request_post.get("created_by")) - if request_post.get("assigned_users"): + if params.get("created_by"): + queryset = queryset.filter(created_by=params.get("created_by")) + if params.get("assigned_users"): queryset = queryset.filter( - users__id__in=json.loads(request_post.get("assigned_users")) + users__id__in=json.loads(params.get("assigned_users")) ) context = {} - search = False - if ( - params.get("team_name") - or params.get("created_by") - or params.get("assigned_users") - ): - search = True - context["search"] = search - results_teams = self.paginate_queryset( queryset.distinct(), self.request, view=self ) teams = TeamsSerializer(results_teams, many=True).data - context["per_page"] = 10 + if results_teams: + offset = queryset.filter(id__gte=results_teams[-1].id).count() + if offset == queryset.count(): + offset = None + else: + offset = 0 context.update( { "teams_count": self.count, - "next": self.get_next_link(), - "previous": self.get_previous_link(), - "page_number": int(self.offset / 10) + 1, + "offset": offset } ) context["teams"] = teams - - users = Profile.objects.filter( - is_active=True, org=self.request.org - ).order_by("id") - context["users"] = ProfileSerializer(users, many=True).data return context @swagger_auto_schema( @@ -109,23 +91,14 @@ def post(self, request, *args, **kwargs): ) serializer = TeamCreateSerializer(data=params, request_obj=request) - data = {} if serializer.is_valid(): team_obj = serializer.save(created_by=request.profile, org=request.org) if params.get("assign_users"): - assinged_to_users_ids = json.loads(params.get("assign_users")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter(id=user_id, org=request.org) - if user.exists(): - team_obj.users.add(user_id) - else: - team_obj.delete() - data["users"] = "Please enter valid user" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + assinged_to_list = json.loads(params.get("assign_users")) + profiles = Profile.objects.filter(id__in=assinged_to_list, org=request.org) + if profiles: + team_obj.users.add(*profiles) return Response( {"error": False, "message": "Team Created Successfully"}, status=status.HTTP_200_OK, @@ -159,10 +132,6 @@ def get(self, request, pk, **kwargs): self.team_obj = self.get_object(pk) context = {} context["team"] = TeamsSerializer(self.team_obj).data - context["users"] = ProfileSerializer( - Profile.objects.filter(is_active=True, org=request.org).order_by("user__email"), - many=True, - ).data return Response(context) @swagger_auto_schema( @@ -188,29 +157,19 @@ def put(self, request, pk, *args, **kwargs): serializer = TeamCreateSerializer( data=params, instance=self.team, request_obj=request ) - data = {} if serializer.is_valid(): team_obj = serializer.save() team_obj.users.clear() if params.get("assign_users"): - assinged_to_users_ids = json.loads(params.get("assign_users")) - for user_id in assinged_to_users_ids: - user = Profile.objects.filter(id=user_id, org=request.org) - if user.exists(): - team_obj.users.add(user_id) - else: - data["users"] = "Please enter valid user" - return Response( - {"error": True, "errors": data}, - status=status.HTTP_400_BAD_REQUEST, - ) + assinged_to_list = json.loads(params.get("assign_users")) + profiles = Profile.objects.filter(id__in=assinged_to_list, org=request.org) + if profiles: + team_obj.users.add(*profiles) update_team_users.delay(pk) latest_users = team_obj.get_users() for user in actual_users: - if user in latest_users: - pass - else: + if user not in latest_users: removed_users.append(user) remove_users.delay(removed_users, pk) return Response(