added profile pic for user model, updated code to upload profile pic in user edit, few changes in list pages (#112)
* updated python version in travis yml file * added 404 & 500 pages, updated text in account, cases, leads, contact, opportunity add edit pages * updated debug to false, added local manage.py file * updated the code to redirect to create page only after clicking on save & new in accounts page, updated text in forgot password * Added the relevant place holders in all the forms, displaying error message in forgot password form * updated django version for security reasons * fixed issue of showing column names if there is no data in list pages, fixed design in comment update section, changed the url of cancel button in user update page * added profile pic for user model, updated code to upload profile pric in user edit, few changes in list pages
This commit is contained in:
parent
56c9a74461
commit
c0576a3d7d
18 changed files with 139 additions and 28 deletions
|
|
@ -236,6 +236,7 @@
|
|||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
{% if contacts|length > 0 %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%" style="text-align:center;">S.No</th>
|
||||
|
|
@ -245,6 +246,7 @@
|
|||
<th width="25%" style="text-align:center;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for contact in contacts %}
|
||||
<tr id="contacts_details{{contact.id}}" class="text-center">
|
||||
|
|
@ -262,6 +264,9 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% ifequal contacts|length 0 %}
|
||||
<h6 class="text-center">No Contact Records Found</h6>
|
||||
{% endifequal %}
|
||||
</div>
|
||||
</div>
|
||||
<br clear="all">
|
||||
|
|
@ -748,6 +753,7 @@
|
|||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
{% if opportunity_list|length > 0 %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%" style="text-align:center;">S.No</th>
|
||||
|
|
@ -757,6 +763,7 @@
|
|||
<th width="25%" style="text-align:center;">Actions </th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for opportunity in opportunity_list %}
|
||||
<tr id="opp_details{{opportunity.id}}" class="text-center">
|
||||
|
|
@ -774,6 +781,9 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`{% ifequal contacts|length 0 %}
|
||||
<h6 class="text-center">No Opportunity Records Found</h6>
|
||||
{% endifequal %}
|
||||
</div>
|
||||
</div>
|
||||
<br clear="all">
|
||||
|
|
@ -1306,6 +1316,7 @@
|
|||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
{% if cases|length > 0 %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%" style="text-align:center;">S.No</th>
|
||||
|
|
@ -1315,6 +1326,7 @@
|
|||
<th width="25%" style="text-align:center;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for case in cases %}
|
||||
<tr id="cases_details{{case.id}}" class="text-center">
|
||||
|
|
@ -1333,6 +1345,9 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% ifequal cases|length 0 %}
|
||||
<h6 class="text-center">No Case Records Found</h6>
|
||||
{% endifequal %}
|
||||
</div>
|
||||
</div>
|
||||
<br clear="all">
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@
|
|||
<table class="table " id="multiselect">
|
||||
<thead>
|
||||
{% if cases|length > 0 %}
|
||||
|
||||
<tr>
|
||||
<th width="5%">S.No</th>
|
||||
<th width="20%">Name</th>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class UserForm(forms.ModelForm):
|
|||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['email', 'first_name', 'last_name', 'username', 'role']
|
||||
fields = ['email', 'first_name', 'last_name', 'username', 'role', 'profile_pic']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(UserForm, self).__init__(*args, **kwargs)
|
||||
|
|
|
|||
19
common/migrations/0004_user_profile_pic.py
Normal file
19
common/migrations/0004_user_profile_pic.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.1.1 on 2018-10-09 06:44
|
||||
|
||||
import common.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('common', '0003_user_role'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='profile_pic',
|
||||
field=models.FileField(blank=True, max_length=1000, null=True, upload_to=common.models.img_url),
|
||||
),
|
||||
]
|
||||
|
|
@ -3,9 +3,16 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager
|
||||
|
||||
from common.utils import COUNTRIES, ROLES
|
||||
import time
|
||||
|
||||
|
||||
def img_url(self, filename):
|
||||
hash_ = int(time.time())
|
||||
return "%s/%s/%s" % ("profile_pics", hash_, filename)
|
||||
|
||||
|
||||
class User(AbstractBaseUser, PermissionsMixin):
|
||||
file_prepend = "users/profile_pics"
|
||||
username = models.CharField(max_length=100, unique=True)
|
||||
first_name = models.CharField(max_length=150, blank=True)
|
||||
last_name = models.CharField(max_length=150, blank=True)
|
||||
|
|
@ -15,6 +22,8 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||
is_staff = models.BooleanField(default=False)
|
||||
date_joined = models.DateTimeField(('date joined'), auto_now_add=True)
|
||||
role = models.CharField(max_length=50, choices=ROLES)
|
||||
profile_pic = models.FileField(max_length=1000, upload_to=img_url, null=True, blank=True)
|
||||
|
||||
|
||||
USERNAME_FIELD = 'email'
|
||||
REQUIRED_FIELDS = ['username', ]
|
||||
|
|
|
|||
|
|
@ -25,21 +25,21 @@
|
|||
<label for="id_firstname">First Name{% if user_form.first_name.field.required %}<span class="error">*</span>{% endif %}</label>
|
||||
<input type="text" class="form-control" name="first_name" value="{% if user_obj %}{{ user_obj.first_name }}{% else %}{{request.POST.first_name}}{% endif %}" placeholder="First Name">
|
||||
</div>
|
||||
<span class="error">{{ errors.first_name }}</span>
|
||||
<span class="error" id="id_first_name">{{ errors.first_name }}</span>
|
||||
</div>
|
||||
<div class="filter_col col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="id_lastname">Last Name{% if user_form.last_name.field.required %}<span class="error">*</span>{% endif %}</label>
|
||||
<input type="text" class="form-control" name="last_name" value="{% if user_obj %}{{ user_obj.last_name }}{% else %}{{request.POST.last_name}} {% endif %}" placeholder="Last Name">
|
||||
</div>
|
||||
<span class="error">{{ errors.last_name }}</span>
|
||||
<span class="error" id="id_last_name">{{ errors.last_name }}</span>
|
||||
</div>
|
||||
<div class="filter_col col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="id_username">Username{% if user_form.username.field.required %}<span class="error">*</span>{% endif %}</label>
|
||||
<input type="text" class="form-control" name="username" value="{% if user_obj %}{{ user_obj.username }}{% else %}{{request.POST.username}}{% endif %}" placeholder="Username">
|
||||
</div>
|
||||
<span class="error">{{ errors.username }}</span>
|
||||
<span class="error" id="id_username">{{ errors.username }}</span>
|
||||
</div>
|
||||
<div class="filter_col col-md-12">
|
||||
<div class="form-group">
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
<input type="text" class="form-control" name="email" value="{% if user_obj %}{{ user_obj.email }}{% else %}{{request.POST.email}}{% endif %}" {% if user_obj %} readonly=""{% endif %} placeholder="Email">
|
||||
|
||||
</div>
|
||||
<span class="error">{{ errors.email }}</span>
|
||||
<span class="error" id="id_email">{{ errors.email }}</span>
|
||||
</div>
|
||||
<div class="filter_col col-md-12" {% if request.user.role != 'ADMIN' and not request.user.is_superuser %}style="display:none;"{% endif %}>
|
||||
<div class="form-group">
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
<option value="{{user_obj.role}}">{{user_obj.role}}</option>
|
||||
</select>
|
||||
{% endif %}
|
||||
<span class="error">{{ user_form.role.errors }}</span>
|
||||
<span class="error" id="id_role">{{ user_form.role.errors }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if not user_obj %}
|
||||
|
|
@ -72,9 +72,17 @@
|
|||
<label for="exampleInputEmail1">Password{% if user_form.password.field.required %}<span class="error">*</span>{% endif %}</label>
|
||||
<input type="password" class="form-control" name="password" value="{{request.POST.password}}" placeholder="Password">
|
||||
</div>
|
||||
<span class="error">{{ errors.password }}</span>
|
||||
<span class="error" id="id_password">{{ errors.password }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="filter_col col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="exampleInputEmail1">Upload Profile Picture{% if user_form.profile_pic.field.required %}<span class="error">*</span>{% endif %}</label>
|
||||
<input type="file" name="profile_pic" accept="image/*" class="form-control" />
|
||||
</div>
|
||||
{% if user_obj %}<span>{{user_obj.profile_pic }}</span>{% endif %}
|
||||
<span class="error" id="id_profile_pic">{{ errors.profile_pic }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row marl buttons_row form_btn_row text-center">
|
||||
|
|
@ -87,3 +95,26 @@
|
|||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
{% block js_block %}
|
||||
<script src="http://malsup.github.com/jquery.form.js"></script>
|
||||
<script type="text/javascript">
|
||||
$('form#add_form').ajaxForm({
|
||||
type:'POST',
|
||||
dataType:'json',
|
||||
url: ".",
|
||||
data:$('#add_form').serialize(),
|
||||
success: function(data) {
|
||||
if(data.error){
|
||||
$('.error').html('')
|
||||
for (var key in data.errors) {
|
||||
$('#id_'+key).html("<p>" + data.errors[key][0] + "</p>");
|
||||
};
|
||||
}
|
||||
else{
|
||||
window.location = data.success_url;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock js_block %}
|
||||
|
|
@ -72,6 +72,7 @@
|
|||
<table class="table table-bordered table-striped table-condensed">
|
||||
<thead>
|
||||
{% if users|length > 0 %}
|
||||
|
||||
<tr>
|
||||
<th width="5%" style="text-align:center;">S.No</th>
|
||||
<th width="20%" style="text-align:center;">First Name</th>
|
||||
|
|
@ -105,7 +106,7 @@
|
|||
</td>
|
||||
<td class="actions">
|
||||
<!-- <a href="{% url 'common:view_user' user.id %}" class="btn btn-info view"><i class="fas fa-eye"></i>View</a> -->
|
||||
{% if request.user.id != user.id and user.email != "admin@micropyramid.com" %}
|
||||
{% if user.email != admin_email or request.user.email == admin_email %}
|
||||
<a href="{% url 'common:edit_user' user.id %}" class="btn btn-success edit"><i class="fas fa-pencil-alt"></i>Edit</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'common:remove_user' user.id %}" class="btn btn-danger trash" {% if request.user.email == user.email or user.role == "ADMIN" or user.is_superuser %} style="visibility: hidden;" {% endif %}><i class="fas fa-trash-alt"></i>Delete</a>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ from django.urls import path, re_path
|
|||
from common.views import (
|
||||
HomeView, LoginView, ForgotPasswordView, LogoutView, ChangePasswordView, ProfileView,
|
||||
UsersListView, CreateUserView, UpdateUserView, UserDetailView, UserDeleteView)
|
||||
from django.conf.urls.static import static
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
app_name = 'common'
|
||||
|
|
@ -32,4 +34,4 @@ urlpatterns = [
|
|||
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
|
||||
|
||||
|
||||
]
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
from django.contrib.auth import logout, authenticate, login
|
||||
from django.contrib.auth.hashers import check_password
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, AccessMixin
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.http import HttpResponseRedirect, JsonResponse
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.views.generic import (
|
||||
CreateView, UpdateView, DetailView, TemplateView, View, DeleteView)
|
||||
from common.models import User
|
||||
from common.forms import UserForm, LoginForm, ChangePasswordForm
|
||||
from django.urls import reverse_lazy
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def handler404(request, exception):
|
||||
|
|
@ -132,6 +134,7 @@ class UsersListView(AdminRequiredMixin, TemplateView):
|
|||
context["active_users"] = self.get_queryset().filter(is_active=True)
|
||||
context["inactive_users"] = self.get_queryset().filter(is_active=False)
|
||||
context["per_page"] = self.request.POST.get('per_page')
|
||||
context['admin_email'] = settings.ADMIN_EMAIL
|
||||
return context
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
|
@ -149,11 +152,17 @@ class CreateUserView(AdminRequiredMixin, CreateView):
|
|||
if form.cleaned_data.get("password"):
|
||||
user.set_password(form.cleaned_data.get("password"))
|
||||
user.save()
|
||||
return redirect("common:users_list")
|
||||
if self.request.is_ajax():
|
||||
data = {'success_url': reverse_lazy('common:users_list'), 'error': False}
|
||||
return JsonResponse(data)
|
||||
return super(CreateUserView, self).form_valid(form)
|
||||
|
||||
|
||||
def form_invalid(self, form):
|
||||
return self.render_to_response(
|
||||
self.get_context_data(form=form, errors=form.errors))
|
||||
response = super(CreateUserView, self).form_invalid(form)
|
||||
if self.request.is_ajax():
|
||||
return JsonResponse({'error': True, 'errors': form.errors})
|
||||
return response
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(CreateUserView, self).get_context_data(**kwargs)
|
||||
|
|
@ -190,12 +199,20 @@ class UpdateUserView(LoginRequiredMixin, UpdateView):
|
|||
user.is_superuser = False
|
||||
user.save()
|
||||
if self.request.user.role == "ADMIN" or self.request.user.is_superuser:
|
||||
return redirect("common:users_list")
|
||||
return redirect("common:profile")
|
||||
if self.request.is_ajax():
|
||||
data = {'success_url': reverse_lazy('common:users_list'), 'error': False}
|
||||
return JsonResponse(data)
|
||||
if self.request.is_ajax():
|
||||
data = {'success_url': reverse_lazy('common:profile'), 'error': False}
|
||||
return JsonResponse(data)
|
||||
return super(UpdateUserView, self).form_valid(form)
|
||||
|
||||
|
||||
def form_invalid(self, form):
|
||||
return self.render_to_response(
|
||||
self.get_context_data(form=form, errors=form.errors))
|
||||
response = super(UpdateUserView, self).form_invalid(form)
|
||||
if self.request.is_ajax():
|
||||
return JsonResponse({'error': True, 'errors': form.errors})
|
||||
return response
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateUserView, self).get_context_data(**kwargs)
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
|
||||
{% if contact_obj_list|length > 0 %}
|
||||
<tr>
|
||||
<th width="5%" >S.no</th>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ INSTALLED_APPS = [
|
|||
'leads',
|
||||
'opportunity',
|
||||
'planner',
|
||||
'sorl.thumbnail',
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -182,3 +183,5 @@ SG_USER = os.getenv('SG_USER', '')
|
|||
SG_PWD = os.getenv('SG_PWD', '')
|
||||
|
||||
MANDRILL_API_KEY = os.getenv('MANDRILL_API_KEY', '')
|
||||
|
||||
ADMIN_EMAIL = "admin@micropyramid.com"
|
||||
|
|
|
|||
|
|
@ -186,7 +186,8 @@
|
|||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">Update Your Comment</h4>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
|
||||
|
||||
</div>
|
||||
<form id="comment_edit_form" method="POST" >
|
||||
<div class="modal-body">
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@
|
|||
<table class="table ">
|
||||
<thead>
|
||||
{% if opportunity_list|length > 0 %}
|
||||
|
||||
<tr>
|
||||
<th width="5%">S.No</th>
|
||||
<th width="15%">Name</th>
|
||||
|
|
|
|||
|
|
@ -168,7 +168,8 @@
|
|||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">Update Your Comment</h4>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
|
||||
|
||||
</div>
|
||||
<form id="comment_edit_form" method="POST" >
|
||||
<div class="modal-body">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Django==2.1.2
|
||||
Django==2.1.1
|
||||
django-simple-pagination==1.1.8
|
||||
pytz==2018.3
|
||||
psycopg2-binary==2.7.4
|
||||
|
|
@ -9,3 +9,5 @@ pytest==3.6.3
|
|||
pytest-cov==2.5.1
|
||||
pytest-django==3.1.2
|
||||
codacy-coverage==1.3.6
|
||||
sorl-thumbnail==12.5.0
|
||||
Pillow==5.3.0
|
||||
|
|
|
|||
|
|
@ -638,7 +638,6 @@ $color_2: #000;
|
|||
.buttons_row{
|
||||
margin:0;
|
||||
position: relative;
|
||||
top: -4px;
|
||||
}
|
||||
.form-control{
|
||||
border-radius: 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{% load staticfiles %}
|
||||
{% load compress %}
|
||||
|
||||
{% load thumbnail %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
|
@ -41,16 +41,16 @@
|
|||
|
||||
<ul class="navbar-nav navbar-right my-2 my-lg-0">
|
||||
<li class="nav-item dropdown">
|
||||
{% with request.profile as profile %}
|
||||
<a href="#" class="dropdown-toggle abcd nav-link" data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||
aria-expanded="false" >
|
||||
{% if not profile.profile_pic %}
|
||||
{% if not request.user.profile_pic %}
|
||||
<img src="{% static 'images/user.png' %}" alt="Micro profile pic">
|
||||
{% else %}
|
||||
<img src="{{profile.profile_pic.url}}" alt="Micro profile pic">
|
||||
{% thumbnail request.user.profile_pic "25x25" as im %}
|
||||
<img src="{{ im.url }}">
|
||||
{% endthumbnail %}
|
||||
{% endif %}
|
||||
<b class="caret"></b></a>
|
||||
{% endwith %}
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
|
||||
{% if request.user.email != "admin@micropyramid.com" %}
|
||||
<a class="dropdown-item" href="/change-password/"><i class="fas fa-key"></i> Change Password</a>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% load thumbnail %}
|
||||
{% block content%}
|
||||
|
||||
<!-- OPPORTUNITY VIEW STARTS -->
|
||||
<div class="main_container" id="maincontainer">
|
||||
<div class="overview_form_block row marl justify-content-center">
|
||||
|
|
@ -21,18 +23,18 @@
|
|||
</div>
|
||||
</span> -->
|
||||
</h5>
|
||||
{% if not request.user.role == "ADMIN" and not request.user.is_superuser %}
|
||||
<a href="{% url 'common:edit_user' user_obj.id %}" class="btn btn-success edit">Edit</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row marl no-gutters">
|
||||
<div class="col-md-8">
|
||||
{% if user_obj.first_name %}
|
||||
<div class="filter_col col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="contact_field_label" for="id_name" data-name="name">Name</label>
|
||||
<div class="contact_field" id="contact_name" data-name="name">{{ user_obj.first_name }} {{ user_obj.last_name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="filter_col col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="contact_field_label" for="id_contact_account" data-name="name">UserName</label>
|
||||
|
|
@ -48,7 +50,13 @@
|
|||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="profile_pic">
|
||||
{% if user_obj.profile_pic %}
|
||||
{% thumbnail request.user.profile_pic "125x125" as im %}
|
||||
<img src="{{ im.url }}">
|
||||
{% endthumbnail %}
|
||||
{% else %}
|
||||
<img src="https://cdn.dribbble.com/users/99875/screenshots/4353558/2018-03-01biker_site-2.gif" />
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue