134 changed files with 18084 additions and 2884 deletions
-
5.gitignore
-
2abonapp/forms.py
-
20abonapp/migrations/0001_initial.py
-
80abonapp/models.py
-
2abonapp/tests.py
-
3abonapp/urls_abon.py
-
10abonapp/views.py
-
21accounts_app/migrations/0001_initial.py
-
7accounts_app/models.py
-
22accounts_app/views.py
-
1agent.py
-
5agent/firewall.py
-
9agent/main.py
-
1agent/models.py
-
4agent/netflow/to_mysql.py
-
2agent/settings.py
-
21agent/sslTransmitter.py
-
4clientsideapp/views.py
-
2cron.py
-
1devapp/base_intr.py
-
1devapp/dev_types.py
-
8devapp/migrations/0001_initial.py
-
3devapp/models.py
-
9djing/settings_example.py
-
3djing/urls.py
-
1global_context_processors.py
-
0gmap/__init__.py
-
43gmap/admin.py
-
2gmap/apps.py
-
20gmap/forms.py
-
0gmap/migrations/__init__.py
-
369gmap/models.py
-
0gmap/tests.py
-
16gmap/urls.py
-
143gmap/utils.py
-
250gmap/views.py
-
31install.sql
-
1ip_pool/migrations/0001_initial.py
-
5ip_pool/models.py
-
4ip_pool/views.py
-
6mapapp/admin.py
-
25mapapp/migrations/0001_initial.py
-
10mapapp/models.py
-
9mapapp/urls.py
-
22mapapp/views.py
-
6mydefs.py
-
1photo_app/migrations/0001_initial.py
-
6photo_app/models.py
-
2photo_app/urls.py
-
7privatemessage/migrations/0001_initial.py
-
1privatemessage/models.py
-
1privatemessage/tests.py
-
6privatemessage/views.py
-
16static/bad_ie.html
-
4static/clientside/custom.css
-
416static/css/bootstrap-datetimepicker.min.css
-
470static/css/bootstrap-theme.min.css
-
7022static/css/bootstrap.min.css
-
106static/css/custom.css
-
50static/css/custom_login.css
-
4static/css/gmap.css
-
694static/js/bootstrap-datetimepicker.min.js
-
703static/js/bootstrap.min.js
-
91static/js/gmap.js
-
2116static/js/jquery-2.2.4.min.js
-
3414static/js/moment-with-locales.min.js
-
84static/js/my.js
-
1statistics/migrations/0001_initial.py
-
2tariff_app/base_intr.py
-
6tariff_app/custom_tariffs.py
-
7tariff_app/migrations/0001_initial.py
-
1tariff_app/models.py
-
55taskapp/forms.py
-
13taskapp/models.py
-
43taskapp/views.py
-
16templates/abonapp/abonamount.html
-
52templates/abonapp/activate_service.html
-
128templates/abonapp/addAbon.html
-
76templates/abonapp/addGroup.html
-
79templates/abonapp/addInvoice.html
-
74templates/abonapp/buy_tariff.html
-
89templates/abonapp/complete_service.html
-
64templates/abonapp/debtors.html
-
14templates/abonapp/editAbon.html
-
38templates/abonapp/ext.htm
-
116templates/abonapp/group_list.html
-
94templates/abonapp/invoiceForPayment.html
-
56templates/abonapp/log.html
-
51templates/abonapp/payHistory.html
-
116templates/abonapp/peoples.html
-
127templates/abonapp/services.html
-
119templates/accounts/acc_list.html
-
166templates/accounts/create_acc.html
-
24templates/accounts/ext.htm
-
77templates/accounts/group.html
-
76templates/accounts/group_list.html
-
16templates/accounts/index.html
-
110templates/accounts/login.html
-
9templates/accounts/profile_chgroup.html
-
27templates/accounts/settings/ch_info.html
@ -0,0 +1,43 @@ |
|||
from django.contrib import admin |
|||
|
|||
from gmap.models import MapMarker, MarkerCategory, MarkerSubCategory, SalesDirector, SalesBoundary, CountryISOCode |
|||
|
|||
|
|||
class MarkerAdmin(admin.ModelAdmin): |
|||
list_display = [ |
|||
'name', |
|||
'contact_title', |
|||
'category', |
|||
'contact_name', |
|||
'airport_code', |
|||
'address', |
|||
'platinum', |
|||
'airport_name', |
|||
'phone', |
|||
'fax', |
|||
'email', |
|||
'url' |
|||
] |
|||
exclude = ('latitude', 'longitude') |
|||
|
|||
|
|||
class MarkerInline(admin.TabularInline): |
|||
model = MapMarker |
|||
exclude = ('latitude', 'longitude') |
|||
extra = 1 |
|||
|
|||
|
|||
class BoundaryAdmin(admin.ModelAdmin): |
|||
list_display = ['boundary_code', 'owner'] |
|||
|
|||
|
|||
class DirectorAdmin(admin.ModelAdmin): |
|||
list_display = ['name', 'country'] |
|||
|
|||
|
|||
admin.site.register(MapMarker, MarkerAdmin) |
|||
admin.site.register(MarkerCategory) |
|||
admin.site.register(MarkerSubCategory) |
|||
admin.site.register(CountryISOCode) |
|||
admin.site.register(SalesDirector, DirectorAdmin) |
|||
admin.site.register(SalesBoundary, BoundaryAdmin) |
|||
@ -0,0 +1,20 @@ |
|||
from django import forms |
|||
|
|||
from gmap.models import MapMarker, CountryISOCode |
|||
|
|||
|
|||
class ModifiedChoiceField(forms.ModelChoiceField): |
|||
def label_from_instance(self, obj): |
|||
if 'long_name' in obj: |
|||
return obj['long_name'] |
|||
|
|||
if 'state' in obj: |
|||
return obj['state'] |
|||
|
|||
return 'No Data' |
|||
|
|||
|
|||
class MapSearchForm(forms.Form): |
|||
state = ModifiedChoiceField( |
|||
queryset=MapMarker.objects.filter(country__iso_3='USA').values('state').order_by('state').distinct(), label='') |
|||
country = ModifiedChoiceField(queryset=CountryISOCode.objects.order_by('long_name').values('long_name'), label='') |
|||
@ -0,0 +1,369 @@ |
|||
from django.db import models |
|||
|
|||
from gmap.utils import geolocate |
|||
|
|||
|
|||
CATEGORY_LOOKUP = {u'1': 'Cirrus Authorized Service Center (ASC)', u'2': 'Cirrus Sales Representative or Center', |
|||
u'3': 'Cirrus Training Center (CTC)', u'4': 'Cirrus Standardized Instructor Pilot (CSIP)'} |
|||
|
|||
INVERSE_CATEGORY = dict((v, k) for k, v in CATEGORY_LOOKUP.iteritems()) |
|||
|
|||
SUBCATEGORY_LOOKUP = { |
|||
|
|||
u'1': 'Composite & Paint Repair', |
|||
u'2': 'Pickup & Delivery Service', |
|||
u'3': 'Parts Distributor', |
|||
u'4': 'Air Conditioning Service', |
|||
u'5': 'Garmin Service', |
|||
u'6': 'Avidyne Service', |
|||
u'7': 'Full Avionics Facility', |
|||
u'8': 'Oxygen Service', |
|||
u'9': 'Wi-Fi Equipped', |
|||
u'10': 'CAPS Overhaul', |
|||
u'11': 'Cirrus Platinum Service Partner', |
|||
u'12': 'Ice Protection System Maintenance', |
|||
u'13': 'SR20 Rental', |
|||
u'14': 'SR22 Rental', |
|||
u'15': 'SR22T Rental', |
|||
u'16': 'Cirrus Perspective Avionics Available', |
|||
u'17': 'Avidyne Entegra Avionics Available', |
|||
u'18': 'Cirrus Platinum Training Partner', |
|||
u'19': 'Simulator Available', |
|||
u'20': 'Cirrus Perspective Qualified', |
|||
u'21': 'Avidyne Entegra Qualified', |
|||
u'22': 'New Cirrus Sales', |
|||
u'23': 'Used Cirrus Sales', |
|||
u'24': 'n/a' |
|||
|
|||
} |
|||
|
|||
INVERSE_SUBCATEGORY = dict((v, k) for k, v in SUBCATEGORY_LOOKUP.iteritems()) |
|||
|
|||
# name, category, platinum partner, contacT_name, contact_title, airport_name, airport_code, address, phone, fax, email, url, sub_category1, ..., sub_categoryN |
|||
|
|||
SUBCAT_IDX = 18 |
|||
# SUBCAT_IDX = 12 |
|||
|
|||
# NAME_COLUMN = 2 |
|||
NAME_COLUMN = 0 |
|||
#CATEGORY_COLUMN = 3 |
|||
CATEGORY_COLUMN = 1 |
|||
#ADDRESS_COLUMN = 9 |
|||
ADDRESS_COLUMN = 7 |
|||
SUBCATEGORY_COLUMN = SUBCAT_IDX |
|||
|
|||
|
|||
class SalesBoundary(models.Model): |
|||
boundary_code = models.CharField('Boundary Code', max_length=75) |
|||
owner = models.ForeignKey('SalesDirector'); |
|||
|
|||
class Meta: |
|||
unique_together = ("boundary_code", "owner") |
|||
|
|||
def __unicode__(self): |
|||
return self.boundary_code |
|||
|
|||
|
|||
class SalesDirector(models.Model): |
|||
name = models.CharField('Name', max_length=100, unique=True) |
|||
title = models.CharField(max_length=50, blank=True) |
|||
phone = models.CharField('Phone Number', max_length=40, blank=True) |
|||
email = models.EmailField('Email', blank=True) |
|||
airport_code = models.CharField(max_length=8, blank=True) |
|||
airport_name = models.CharField(max_length=50, blank=True) |
|||
address = models.TextField(max_length=200, blank=True) |
|||
city = models.CharField(max_length=200, blank=True) |
|||
state = models.CharField(max_length=100, blank=True) |
|||
zipcode = models.CharField(max_length=10, blank=True) |
|||
url = models.URLField(blank=True) |
|||
country = models.ForeignKey('CountryISOCode', blank=True) |
|||
|
|||
def from_csv(self, row, row_id, errors): |
|||
|
|||
local_errors = False |
|||
|
|||
''' |
|||
self.name, cat, plat, self.contact_name, self.contact_title = row[0:5] |
|||
self.airport_name, self.airport_code, self.address, self.phone, self.fax = row[5:10] |
|||
self.email, self.url = row[10:12] |
|||
|
|||
subcategories = row[12:] |
|||
''' |
|||
|
|||
cat, plat = '', '' |
|||
subcategories = [] |
|||
|
|||
try: |
|||
|
|||
self.name, cat, plat, self.contact_name, self.title = row[0:5] |
|||
self.airport_name, self.airport_code, self.address, self.phone, fax = row[5:10] |
|||
self.email, self.url, self.state, iso_3, self.city, self.zipcode, latitude, longitude = row[10:SUBCAT_IDX] |
|||
|
|||
subcat_string = row[SUBCAT_IDX] |
|||
|
|||
if ',' in subcat_string: |
|||
subcategories = subcat_string.split(',') |
|||
|
|||
else: |
|||
subcategories = [subcat_string] |
|||
|
|||
except IndexError: |
|||
error_string = "Entry does not contain required number of fields: %s < %s" % (len(row), SUBCAT_IDX) |
|||
errors.append(('%s : %s' % (row_id, error_string))) |
|||
return |
|||
|
|||
except ValueError: |
|||
error_string = "Entry does not contain required number of fields: %s < %s" % (len(row), SUBCAT_IDX) |
|||
errors.append(('%s : %s' % (row_id, error_string))) |
|||
return |
|||
|
|||
if not self.name: |
|||
local_errors = True |
|||
row[NAME_COLUMN] = '<font color="red">INSERT_NAME</font>' |
|||
|
|||
if local_errors: |
|||
error_string = ', '.join(row) |
|||
errors.append(('%s : %s' % (row_id, error_string))) |
|||
return |
|||
|
|||
try: |
|||
self.country = CountryISOCode.objects.get(long_name=iso_3) |
|||
|
|||
except: |
|||
|
|||
try: |
|||
self.country = CountryISOCode.objects.get(iso_3=iso_3) |
|||
|
|||
except: |
|||
|
|||
try: |
|||
self.country = CountryISOCode.objects.get(iso_2=iso_3) |
|||
|
|||
except: |
|||
error_string = "Unable to map %s to ISO long name, two letter abbreviation, or three letter abbreviation" % iso_3 |
|||
errors.append(('%s : %s' % (row_id, error_string))) |
|||
|
|||
# Ask django really, really nicely not to insert our object twice |
|||
self.save() |
|||
|
|||
def __unicode__(self): |
|||
return self.name |
|||
|
|||
|
|||
class MarkerCategoryManager(models.Manager): |
|||
def get_by_natural_key(self, name): |
|||
return self.get(name=name) |
|||
|
|||
|
|||
class MarkerCategory(models.Model): |
|||
objects = MarkerCategoryManager() |
|||
name = models.CharField('type', max_length=200, unique=True) |
|||
position = models.IntegerField(default=0); |
|||
icon = models.ImageField('icon', blank=True, upload_to='gmap-icons/') |
|||
platinum_icon = models.ImageField('platinum icon', blank=True, upload_to='gmap-icons/') |
|||
shadow = models.ImageField('icon shadow', blank=True, upload_to='gmap-icons/') |
|||
|
|||
def natural_key(self): |
|||
return self.name |
|||
|
|||
def __unicode__(self): |
|||
return self.name |
|||
|
|||
|
|||
class MarkerSubCategory(models.Model): |
|||
objects = MarkerCategoryManager() |
|||
name = models.CharField('Name', max_length=200, unique=True) |
|||
|
|||
def natural_key(self): |
|||
return self.name |
|||
|
|||
def __unicode__(self): |
|||
return self.name |
|||
|
|||
|
|||
class GeolocateFailure(Exception): |
|||
def __init__(self, message, address): |
|||
self.message = message |
|||
self.address = address |
|||
|
|||
def __str__(self): |
|||
return '%s - %s' % (self.message, self.address) |
|||
|
|||
|
|||
class CountryISOCode(models.Model): |
|||
long_name = models.CharField(max_length=200) |
|||
iso_3 = models.CharField(max_length=10, blank=True) |
|||
iso_2 = models.CharField(max_length=10, blank=True) |
|||
|
|||
def natural_key(self): |
|||
return self.long_name |
|||
|
|||
def __unicode__(self): |
|||
return self.long_name |
|||
|
|||
|
|||
class MapMarker(models.Model): |
|||
name = models.CharField(max_length=200) |
|||
latitude = models.CharField(max_length=30, blank=True) |
|||
longitude = models.CharField(max_length=30, blank=True) |
|||
category = models.ForeignKey('MarkerCategory') |
|||
platinum = models.BooleanField('Platinum Partner', default=False) |
|||
sub_categories = models.ManyToManyField(MarkerSubCategory, related_name='sub_categories') |
|||
contact_name = models.CharField(max_length=50, blank=True) |
|||
contact_title = models.CharField(max_length=50, blank=True) |
|||
airport_name = models.CharField(max_length=100, blank=True) |
|||
airport_code = models.CharField(max_length=6, blank=True) |
|||
address = models.TextField(max_length=200, blank=True) |
|||
city = models.CharField(max_length=200, blank=True) |
|||
state = models.CharField(max_length=50, blank=True) |
|||
zipcode = models.CharField(max_length=10, blank=True) |
|||
country = models.ForeignKey('CountryISOCode', null=True, blank=True) |
|||
phone = models.CharField(max_length=40, blank=True) |
|||
fax = models.CharField(max_length=40, blank=True) |
|||
email = models.EmailField(blank=True) |
|||
url = models.URLField(blank=True) |
|||
|
|||
# Make sure we update the lat/long with the location |
|||
def save(self, *args, **kwargs): |
|||
|
|||
if not self.latitude and not self.longitude: |
|||
full_address = "%s, %s, %s, %s, %s" % (self.address, self.city, self.state, self.zipcode, self.country) |
|||
latlng = geolocate(repr(full_address)) |
|||
|
|||
if latlng != None: |
|||
self.latitude = latlng['latitude'] |
|||
self.longitude = latlng['longitude'] |
|||
|
|||
else: |
|||
raise GeolocateFailure("Failed to geolocate address for %s" % self.name, full_address) |
|||
|
|||
super(MapMarker, self).save(*args, **kwargs) |
|||
|
|||
def __unicode__(self): |
|||
return self.name |
|||
|
|||
def from_csv(self, row, row_id, errors): |
|||
|
|||
local_errors = False |
|||
|
|||
''' |
|||
self.name, cat, plat, self.contact_name, self.contact_title = row[0:5] |
|||
self.airport_name, self.airport_code, self.address, self.phone, self.fax = row[5:10] |
|||
self.email, self.url = row[10:12] |
|||
|
|||
subcategories = row[12:] |
|||
''' |
|||
|
|||
cat, plat = '', '' |
|||
subcategories = [] |
|||
|
|||
try: |
|||
|
|||
self.name, cat, plat, self.contact_name, self.contact_title = row[0:5] |
|||
self.airport_name, self.airport_code, self.address, self.phone, self.fax = row[5:10] |
|||
self.email, self.url, self.state, iso_3, self.city, self.zipcode, self.latitude, self.longitude = row[ |
|||
10:SUBCAT_IDX] |
|||
|
|||
subcat_string = row[SUBCAT_IDX] |
|||
|
|||
if ',' in subcat_string: |
|||
subcategories = subcat_string.split(',') |
|||
|
|||
else: |
|||
subcategories = [subcat_string] |
|||
|
|||
except IndexError: |
|||
error_string = "Entry does not contain required number of fields: %s < %s" % (len(row), SUBCAT_IDX) |
|||
errors.append(('%s : %s' % (row_id, error_string))) |
|||
return |
|||
|
|||
except ValueError: |
|||
error_string = "Entry does not contain required number of fields: %s < %s" % (len(row), SUBCAT_IDX) |
|||
errors.append(('%s : %s' % (row_id, error_string))) |
|||
return |
|||
|
|||
if not self.name: |
|||
local_errors = True |
|||
row[NAME_COLUMN] = '<font color="red">INSERT_NAME</font>' |
|||
|
|||
if not cat: |
|||
local_errors = True |
|||
row[CATEGORY_COLUMN] = '<font color="red">INSERT_CATEGORY</font>' |
|||
|
|||
#if not self.address: |
|||
# local_errors = True |
|||
# row[ADDRESS_COLUMN] = '<font color="red">INSERT_ADDRESS</font>' |
|||
|
|||
if not len(subcategories): |
|||
local_errors = True |
|||
row.append('<font color="red">INSERT_SUBCATEGORY</font>') |
|||
|
|||
elif not subcategories[0]: |
|||
local_errors = True |
|||
row[SUBCATEGORY_COLUMN] = '<font color="red">INSERT_SUBCATEGORY</font>' |
|||
|
|||
if local_errors: |
|||
error_string = ', '.join(row) |
|||
errors.append(('%s : %s' % (row_id, error_string))) |
|||
return |
|||
|
|||
self.platinum = True if plat == '1' else False |
|||
|
|||
self.category = MarkerCategory.objects.get(pk=cat.strip().strip("'")) |
|||
|
|||
try: |
|||
self.country = CountryISOCode.objects.get(long_name=iso_3) |
|||
|
|||
except: |
|||
|
|||
try: |
|||
self.country = CountryISOCode.objects.get(iso_3=iso_3) |
|||
|
|||
except: |
|||
|
|||
try: |
|||
self.country = CountryISOCode.objects.get(iso_2=iso_3) |
|||
|
|||
except: |
|||
error_string = "Unable to map %s to ISO long name, two letter abbreviation, or three letter abbreviation" % iso_3 |
|||
errors.append(('%s : %s' % (row_id, error_string))) |
|||
|
|||
# object's gotta be in the DB before it can get M2M mapping... |
|||
# |
|||
try: |
|||
self.save() |
|||
|
|||
except GeolocateFailure as inst: |
|||
errors.append('%s : %s' % (row_id, inst)) |
|||
return |
|||
|
|||
# ...like this one! |
|||
for subcategory in subcategories: |
|||
if subcategory: |
|||
self.sub_categories.add(MarkerSubCategory.objects.get(pk=subcategory.strip().strip("'"))) |
|||
|
|||
|
|||
# Ask django really, really nicely not to insert our object twice |
|||
self.save(force_update=True) |
|||
|
|||
# Expected csv format: |
|||
# |
|||
# name, category, platinum partner, contacT_name, contact_title, airport_name, airport_code, address, phone, fax, email, url, sub_category1, ..., sub_categoryN |
|||
# |
|||
def csv_row(self): |
|||
|
|||
# my baseline doesn't have: plat partner, contact_name, contact_title, airport_name, |
|||
# TODO: now it does! |
|||
|
|||
''' |
|||
return [self.latitude, self.longitude, self.name, INVERSE_CATEGORY[self.category.name], str(self.platinum), self.contact_name, self.contact_title, |
|||
self.airport_name, self.airport_code, self.address, self.phone, self.fax, |
|||
self.email, self.url] + [INVERSE_SUBCATEGORY[subcat.name] for subcat in self.sub_categories.all()] |
|||
''' |
|||
|
|||
return [self.name, INVERSE_CATEGORY[self.category.name], str(self.platinum), self.contact_name, |
|||
self.contact_title, |
|||
self.airport_name, self.airport_code, self.address, self.phone, self.fax, |
|||
self.email, self.url] + [INVERSE_SUBCATEGORY[subcat.name] for subcat in self.sub_categories.all()] |
|||
|
|||
|
|||
@ -0,0 +1,16 @@ |
|||
from django.conf.urls import url |
|||
|
|||
from gmap.views import index, showmap, markers, gmap_search, categories, dump_csv, director_by_boundary, director_import |
|||
|
|||
|
|||
app_name = 'gmap' |
|||
urlpatterns = [ |
|||
url(r'^$', index, name="index"), |
|||
url(r'^markers.json$', markers, name="markers"), |
|||
url(r'^categories.json$', categories, name="categories"), |
|||
url(r'^directors/(?P<boundary_code>.+)/$', director_by_boundary, name="directors"), |
|||
url(r'^boundary_import/$', director_import, name="boundary_import"), |
|||
url(r'^search/?', gmap_search, name="gmap_search"), |
|||
url(r'^(?P<address>\w+)$', showmap, name="show_map"), |
|||
url(r'^csv/?', dump_csv, name="dump_csv"), |
|||
] |
|||
@ -0,0 +1,143 @@ |
|||
import json |
|||
import urllib |
|||
import urllib2 |
|||
import csv |
|||
import codecs |
|||
import cStringIO |
|||
|
|||
|
|||
def csvByLine(csvFile, lineHandler): |
|||
errors = '' |
|||
for row_id, line in enumerate(UnicodeReader(csvFile)): |
|||
print "Calling Line handler for %s" % line |
|||
errors = ''.join([errors, lineHandler(line)]) |
|||
return errors |
|||
|
|||
|
|||
def geolocate(location, sensor=False): |
|||
""" |
|||
Take a "location" and return its latitude and longitude |
|||
|
|||
Keyword arguments: |
|||
location - String defining a geographical location (address, zip code, etc) |
|||
sensor - Boolean defining whether the location was taken from |
|||
an on-device sensor |
|||
|
|||
Output: |
|||
latitude and logitude in an dict |
|||
""" |
|||
sensor = str(sensor).lower() |
|||
url = "http://maps.googleapis.com/maps/api/geocode/json?" |
|||
url += urllib.urlencode({'address': location, 'sensor': sensor}) |
|||
data = urllib2.urlopen(url).read() |
|||
data = json.loads(data) |
|||
if data and data['status'] == 'OK': |
|||
return ({ |
|||
'latitude': data['results'][0]['geometry']['location']['lat'], |
|||
'longitude': data['results'][0]['geometry']['location']['lng'] |
|||
}) |
|||
else: |
|||
return None |
|||
|
|||
|
|||
def georeverse(lat, lon): |
|||
# construct url for reverse geocoding with google-maps |
|||
url = "http://maps.googleapis.com/maps/api/geocode/json?" |
|||
url += urllib.urlencode({'latlng': lat + ',' + lon, 'sensor': 'false'}) |
|||
|
|||
# retrieve and load google-map data |
|||
data = urllib2.urlopen(url).read() |
|||
data = json.loads(data) |
|||
|
|||
# if request goes through, return the state and country of the location |
|||
if data['status'] == 'OK': |
|||
address_components = data['results'][0]['address_components'] |
|||
|
|||
# these probably shouldn't be booleans (test with None data-type at some point) |
|||
country = False |
|||
state = False |
|||
|
|||
for component in address_components: |
|||
|
|||
try: |
|||
if component['types'][0] == 'country': |
|||
country = component['long_name'] |
|||
|
|||
if component['types'][0] == 'administrative_area_level_1': |
|||
state = component['long_name'] |
|||
except Exception: |
|||
pass |
|||
|
|||
return ({ |
|||
'state': state, |
|||
'country': country |
|||
}) |
|||
return ({ |
|||
'state': False, |
|||
'country': False |
|||
}) |
|||
|
|||
|
|||
class UTF8Recoder: |
|||
""" |
|||
Iterator that reads an encoded stream and reencodes the input to UTF-8 |
|||
""" |
|||
|
|||
def __init__(self, f, encoding): |
|||
self.reader = codecs.getreader(encoding)(f) |
|||
|
|||
def __iter__(self): |
|||
return self |
|||
|
|||
def next(self): |
|||
# return self.reader.next().decode("cp1252").encode("utf-8") |
|||
return self.reader.next().encode("utf-8") |
|||
|
|||
|
|||
class UnicodeReader: |
|||
""" |
|||
A CSV reader which will iterate over lines in the CSV file "f", |
|||
which is encoded in the given encoding. |
|||
""" |
|||
|
|||
# def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds): |
|||
def __init__(self, f, dialect=csv.excel, encoding="cp1252", **kwds): |
|||
f = UTF8Recoder(f, encoding) |
|||
self.reader = csv.reader(f, dialect=dialect, **kwds) |
|||
|
|||
def next(self): |
|||
row = self.reader.next() |
|||
return [unicode(s, "utf-8") for s in row] |
|||
|
|||
def __iter__(self): |
|||
return self |
|||
|
|||
|
|||
class UnicodeWriter: |
|||
""" |
|||
A CSV writer which will write rows to CSV file "f", |
|||
which is encoded in the given encoding. |
|||
""" |
|||
|
|||
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds): |
|||
# Redirect output to a queue |
|||
self.queue = cStringIO.StringIO() |
|||
self.writer = csv.writer(self.queue, dialect=dialect, **kwds) |
|||
self.stream = f |
|||
self.encoder = codecs.getincrementalencoder(encoding)() |
|||
|
|||
def writerow(self, row): |
|||
self.writer.writerow([s.encode("utf-8") for s in row]) |
|||
# Fetch UTF-8 output from the queue ... |
|||
data = self.queue.getvalue() |
|||
data = data.decode("utf-8") |
|||
# ... and reencode it into the target encoding |
|||
data = self.encoder.encode(data) |
|||
# write to the target stream |
|||
self.stream.write(data) |
|||
# empty queue |
|||
self.queue.truncate(0) |
|||
|
|||
def writerows(self, rows): |
|||
for row in rows: |
|||
self.writerow(row) |
|||
@ -0,0 +1,250 @@ |
|||
import csv |
|||
import tempfile |
|||
import time |
|||
|
|||
from django.conf import settings |
|||
from django.core import serializers |
|||
from django.http import HttpResponse, HttpResponseRedirect |
|||
from django.shortcuts import render, render_to_response |
|||
|
|||
from gmap.utils import geolocate, georeverse, csvByLine |
|||
from gmap.models import MapMarker, MarkerCategory, SalesDirector, SalesBoundary |
|||
from gmap.forms import MapSearchForm |
|||
import gmap.utils |
|||
|
|||
|
|||
def index(request): |
|||
form = MapSearchForm() |
|||
response = render(request, 'maps/gmap.html', {'form': form}) |
|||
response['Cache-Control'] = 'no-cache' |
|||
return response |
|||
|
|||
|
|||
def newsales(args): |
|||
try: |
|||
director_name, code = tuple(args) |
|||
except: |
|||
err = open("Errors.log", "a") |
|||
err_text = "Issues getting tuple from: %s\n" % args |
|||
err.write(err_text) |
|||
err.close() |
|||
return err_text |
|||
|
|||
director, new_director = SalesDirector.objects.get_or_create(name=director_name) |
|||
boundary, created = SalesBoundary.objects.get_or_create(boundary_code=code, owner=director) |
|||
|
|||
if (new_director): |
|||
err = open("Errors.log", "a") |
|||
err_text = "We had to make a new director named: %s\n" % director_name |
|||
err.write(err_text) |
|||
err.close() |
|||
return err_text |
|||
return "" |
|||
|
|||
|
|||
def director_import(request): |
|||
errors = csvByLine(request.FILES['datafile'], newsales) |
|||
return HttpResponse(errors.replace('\n', '<br />')) |
|||
|
|||
|
|||
def showmap(request, address='', category=''): |
|||
context = {} |
|||
context['media_url'] = settings.MEDIA_URL |
|||
|
|||
if request.method == 'POST': |
|||
address = request.POST.get('address', address) |
|||
category = request.POST.get('category', category) |
|||
if request.method == 'GET': |
|||
address = request.GET.get('address', address) |
|||
category = request.GET.get('category', category) |
|||
|
|||
if category: |
|||
context['gmap_markers'] = MapMarker.objects.get( |
|||
marker_type__category_name__iexact=category |
|||
) |
|||
else: |
|||
context['gmap_markers'] = MapMarker.objects.all() |
|||
|
|||
if address: |
|||
latlng = geolocate(address) |
|||
if latlng: |
|||
context['gmap_center_lat'] = latlng['latitude'] |
|||
context['gmap_center_lng'] = latlng['longitude'] |
|||
else: |
|||
context['error'] = "Please try another address." |
|||
|
|||
return render(request, 'maps/gmap.html', context) |
|||
|
|||
|
|||
def markers(request): |
|||
# Show all categories but Sales Centers |
|||
data = serializers.serialize("json", MapMarker.objects.all().order_by('category__position', 'city'), |
|||
use_natural_keys=True) |
|||
return HttpResponse(data, mimetype='applicaton/javascript') |
|||
|
|||
|
|||
def categories(request): |
|||
data = serializers.serialize("json", MarkerCategory.objects.all().order_by('position'), use_natural_keys=True) |
|||
return HttpResponse(data, mimetype='applicaton/javascript') |
|||
|
|||
|
|||
def director_by_boundary(request, boundary_code): |
|||
# get a director based on a boundarycode (zip/postal/country code) |
|||
data = serializers.serialize("json", SalesDirector.objects.filter(salesboundary__boundary_code=boundary_code), |
|||
use_natural_keys=True) |
|||
return HttpResponse(data, mimetype='applicaton/javascript') |
|||
|
|||
|
|||
def gmap_search(request): |
|||
context = {} |
|||
return render(request, 'maps/gmap_search.html', context) |
|||
|
|||
|
|||
def dump_csv(request): |
|||
all_markers = MapMarker.objects.all() |
|||
|
|||
print '# markers: ', len(all_markers) |
|||
|
|||
# all_markers should now have all the things... |
|||
response = HttpResponse(mimetype='text/csv') |
|||
response['Content-Disposition'] = 'attachment; filename=map_markers.csv' |
|||
|
|||
# writer = csv.writer(response, quoting=csv.QUOTE_MINIMAL, lineterminator='\n') |
|||
writer = gmap.utils.UnicodeWriter(response, quoting=csv.QUOTE_MINIMAL, lineterminator='\n') |
|||
|
|||
for marker in all_markers: |
|||
row = marker.csv_row() |
|||
# print 'row is: ', row |
|||
|
|||
# repr because there are non-ascii characters somewhere |
|||
writer.writerow(row) |
|||
|
|||
''' |
|||
writer.writerow(['First row', 'Foo', 'Bar', 'Baz']) |
|||
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"]) |
|||
''' |
|||
|
|||
return response |
|||
|
|||
|
|||
def populatefields(request): |
|||
all_markers = MapMarker.objects.all() |
|||
start_time = time.time() |
|||
|
|||
# loop over all map markers and update their state and country fields |
|||
for marker in all_markers: |
|||
reverse_addy = georeverse(marker.latitude, marker.longitude) |
|||
|
|||
if reverse_addy['country']: |
|||
marker.country = reverse_addy['country'] |
|||
|
|||
if reverse_addy['state']: |
|||
marker.state = reverse_addy['state'] |
|||
|
|||
marker.save() |
|||
|
|||
end_time = time.time() |
|||
return HttpResponse(end_time - start_time) |
|||
|
|||
|
|||
def process_sales_row(row_id, row, errors): |
|||
try: |
|||
sales_director = SalesDirector.objects.get(name=row[0]) |
|||
|
|||
except SalesDirector.DoesNotExist: |
|||
sales_director = SalesDirector() |
|||
|
|||
sales_director.from_csv(row, row_id + 1, errors) |
|||
|
|||
|
|||
def process_marker_row(row_id, row, errors): |
|||
try: |
|||
marker = MapMarker.objects.get(name=row[0], zipcode=row[15]) |
|||
|
|||
except: |
|||
marker = MapMarker() |
|||
|
|||
marker.from_csv(row, row_id + 1, errors) |
|||
|
|||
|
|||
# TODO: return errors? |
|||
def process_row(row_id, row, errors): |
|||
if row[1] == '2': |
|||
|
|||
process_sales_row(row_id, row, errors) |
|||
|
|||
else: |
|||
|
|||
process_marker_row(row_id, row, errors) |
|||
|
|||
|
|||
def read_csv(request): |
|||
if request.method == 'POST' and request.FILES.has_key('datafile'): |
|||
|
|||
# it's conceivable the user could upload a file large enough |
|||
# it gets split into chunks - to handle this we just direct all |
|||
# the chunks to a temp file and process that |
|||
|
|||
# note that the tempfile will be deleted as soon as |
|||
# the with block is completes |
|||
num_processed = -1 |
|||
delta = 0 |
|||
errors = [] |
|||
|
|||
if request.FILES['datafile'].multiple_chunks(): |
|||
MapMarker.objects.all().delete() |
|||
|
|||
delta = time.clock() |
|||
|
|||
with tempfile.TemporaryFile() as local_file: |
|||
|
|||
for chunk in request.FILES['datafile'].chunks(): |
|||
local_file.write(chunk) |
|||
|
|||
local_file.seek(0) |
|||
|
|||
for row_id, row in enumerate(gmap.utils.UnicodeReader(local_file)): |
|||
|
|||
try: |
|||
process_row(row_id, row, errors) |
|||
|
|||
except Exception as inst: |
|||
errors.append("%s : Unable to import entry - %s" % (row_id, inst)) |
|||
|
|||
num_processed = row_id |
|||
|
|||
delta = time.clock() - delta |
|||
|
|||
else: |
|||
|
|||
delta = time.clock() |
|||
|
|||
for row_id, row in enumerate(gmap.utils.UnicodeReader(request.FILES['datafile'])): |
|||
# try: |
|||
process_row(row_id, row, errors) |
|||
|
|||
# except Exception as inst: |
|||
# errors.append("%s : Unable to import entry - %s" % (row_id, inst)) |
|||
|
|||
num_processed = row_id |
|||
|
|||
delta = time.clock() - delta |
|||
|
|||
if len(errors) > 1: |
|||
# Strip off errors result from Excel export garbage (the bottom two entries) |
|||
# |
|||
bottoms = errors[-2:] |
|||
rows = [row.split(':')[0].strip() for row in bottoms] |
|||
|
|||
if int(rows[0]) == row_id: |
|||
errors = errors[0:-2] |
|||
|
|||
if errors: |
|||
return render_to_response('maps/gmap_import_errors.html', {'errors': errors}) |
|||
|
|||
else: |
|||
return HttpResponseRedirect('/gmap/mapmarker/') |
|||
|
|||
else: |
|||
# todo - can I make django redirect to referring page? |
|||
return HttpResponseRedirect('/gmap/') |
|||
@ -1,17 +1,18 @@ |
|||
create table flowstat ( |
|||
`id` int(10) AUTO_INCREMENT NOT NULL, |
|||
`src_ip` CHAR(8) NOT NULL, |
|||
`dst_ip` CHAR(8) NOT NULL, |
|||
`proto` smallint(2) unsigned NOT NULL DEFAULT 0, |
|||
`src_port` smallint(5) unsigned NOT NULL DEFAULT 0, |
|||
`dst_port` smallint(5) unsigned NOT NULL DEFAULT 0, |
|||
`octets` INT unsigned NOT NULL DEFAULT 0, |
|||
`packets` INT unsigned NOT NULL DEFAULT 0, |
|||
PRIMARY KEY (`id`) |
|||
) ENGINE=MyISAM DEFAULT CHARSET=utf8; |
|||
CREATE TABLE flowstat ( |
|||
`id` INT(10) AUTO_INCREMENT NOT NULL, |
|||
`src_ip` CHAR(8) NOT NULL, |
|||
`dst_ip` CHAR(8) NOT NULL, |
|||
`proto` SMALLINT(2) UNSIGNED NOT NULL DEFAULT 0, |
|||
`src_port` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0, |
|||
`dst_port` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0, |
|||
`octets` INT UNSIGNED NOT NULL DEFAULT 0, |
|||
`packets` INT UNSIGNED NOT NULL DEFAULT 0, |
|||
PRIMARY KEY (`id`) |
|||
) |
|||
ENGINE =MyISAM |
|||
DEFAULT CHARSET =utf8; |
|||
|
|||
|
|||
|
|||
INSERT INTO flowstat(`src_ip`, `dst_ip`, `proto`, `src_port`, `dst_port`, `octets`, `packets`) VALUES |
|||
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13), |
|||
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13) |
|||
INSERT INTO flowstat (`src_ip`, `dst_ip`, `proto`, `src_port`, `dst_port`, `octets`, `packets`) VALUES |
|||
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13), |
|||
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13) |
|||
@ -1,6 +0,0 @@ |
|||
from django.contrib import admin |
|||
|
|||
import models |
|||
|
|||
|
|||
admin.site.register(models.Dot) |
|||
@ -1,25 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9 on 2016-06-28 23:51 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
initial = True |
|||
|
|||
dependencies = [ |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.CreateModel( |
|||
name='Dot', |
|||
fields=[ |
|||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|||
('title', models.CharField(max_length=64)), |
|||
('posX', models.FloatField()), |
|||
('posY', models.FloatField()), |
|||
], |
|||
), |
|||
] |
|||
@ -1,10 +0,0 @@ |
|||
from django.db import models |
|||
|
|||
|
|||
class Dot(models.Model): |
|||
title = models.CharField(max_length=64) |
|||
posX = models.FloatField() |
|||
posY = models.FloatField() |
|||
|
|||
def __unicode__(self): |
|||
return self.title |
|||
@ -1,9 +0,0 @@ |
|||
from django.conf.urls import url |
|||
|
|||
import views |
|||
|
|||
|
|||
urlpatterns = [ |
|||
url(r'^$', views.home, name='maps_home_link'), |
|||
url(r'^get_dots$', views.get_dots, name='maps_get_dots') |
|||
] |
|||
@ -1,22 +0,0 @@ |
|||
from json import dumps |
|||
|
|||
from django.contrib.auth.decorators import login_required |
|||
from django.http import HttpResponse |
|||
from django.shortcuts import render |
|||
|
|||
from models import Dot |
|||
from mydefs import only_admins |
|||
|
|||
|
|||
@login_required |
|||
@only_admins |
|||
def home(request): |
|||
return render(request, 'maps/index.html') |
|||
|
|||
|
|||
|
|||
def get_dots(r): |
|||
dots = Dot.objects.all() |
|||
return HttpResponse(dumps({ |
|||
'dots': map(lambda d: (d.id, d.posX, d.posY, d.title), dots) |
|||
})) |
|||
@ -1,11 +1,11 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>Старый браузер</title> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h1>У вас старый ослик, обновитесь хотяб до IE10</h1> |
|||
</body> |
|||
<head> |
|||
<title>Старый браузер</title> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h1>У вас старый ослик, обновитесь хотяб до IE10</h1> |
|||
</body> |
|||
</html> |
|||
416
static/css/bootstrap-datetimepicker.min.css
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
470
static/css/bootstrap-theme.min.css
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
7022
static/css/bootstrap.min.css
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,40 +1,46 @@ |
|||
body { |
|||
padding-top: 40px; |
|||
padding-bottom: 40px; |
|||
background-color: #eee; |
|||
padding-top: 40px; |
|||
padding-bottom: 40px; |
|||
background-color: #eee; |
|||
} |
|||
|
|||
.form-signin { |
|||
max-width: 330px; |
|||
padding: 15px; |
|||
margin: 0 auto; |
|||
max-width: 330px; |
|||
padding: 15px; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.form-signin .form-signin-heading, |
|||
.form-signin .checkbox { |
|||
margin-bottom: 10px; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.form-signin .checkbox { |
|||
font-weight: normal; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
.form-signin .form-control { |
|||
position: relative; |
|||
height: auto; |
|||
-webkit-box-sizing: border-box; |
|||
-moz-box-sizing: border-box; |
|||
box-sizing: border-box; |
|||
padding: 10px; |
|||
font-size: 16px; |
|||
position: relative; |
|||
height: auto; |
|||
-webkit-box-sizing: border-box; |
|||
-moz-box-sizing: border-box; |
|||
box-sizing: border-box; |
|||
padding: 10px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.form-signin .form-control:focus { |
|||
z-index: 2; |
|||
z-index: 2; |
|||
} |
|||
|
|||
.form-signin input[type="email"] { |
|||
margin-bottom: -1px; |
|||
border-bottom-right-radius: 0; |
|||
border-bottom-left-radius: 0; |
|||
margin-bottom: -1px; |
|||
border-bottom-right-radius: 0; |
|||
border-bottom-left-radius: 0; |
|||
} |
|||
|
|||
.form-signin input[type="password"] { |
|||
margin-bottom: 10px; |
|||
border-top-left-radius: 0; |
|||
border-top-right-radius: 0; |
|||
margin-bottom: 10px; |
|||
border-top-left-radius: 0; |
|||
border-top-right-radius: 0; |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
#gmap_canvas { |
|||
width: 500px; |
|||
height: 300px; |
|||
} |
|||
694
static/js/bootstrap-datetimepicker.min.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
703
static/js/bootstrap.min.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,91 @@ |
|||
function toggleCategory(category) { |
|||
$.each(gmap_markers, function (key, marker) { |
|||
if (marker.category == category) { |
|||
if (marker.getVisible() == true) { |
|||
marker.setVisible(false) |
|||
} else { |
|||
marker.setVisible(true) |
|||
} |
|||
} |
|||
}) |
|||
} |
|||
|
|||
function toggleTag(tag) { |
|||
$.each(gmap_markers, function (key, marker) { |
|||
$.each(marker.tags, function (key, this_tag) { |
|||
if (this_tag == tag) { |
|||
if (marker.getVisible() == true) { |
|||
marker.setVisible(false) |
|||
} else { |
|||
marker.setVisible(true) |
|||
} |
|||
} |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
var myLatlng = new Array(); |
|||
var open_marker = ''; |
|||
|
|||
myLatlng[0] = new google.maps.LatLng(28.5000, -81.4500); |
|||
|
|||
var map = new google.maps.Map(document.getElementById("gmap_canvas"), { |
|||
zoom: 1, |
|||
center: myLatlng[0], |
|||
mapTypeId: google.maps.MapTypeId.ROADMAP |
|||
}); |
|||
|
|||
$.getJSON('/map/markers.json', function (data) { |
|||
var categories = new Array(); |
|||
var tags = new Array(); |
|||
var infowindow = new google.maps.InfoWindow({content: ''}) |
|||
gmap_markers = [] |
|||
$.each(data, function (key, item) { |
|||
var content = '<span class="name">' + item.fields.name + '</span><br/><span class="phone">' + item.fields.phone + '</span><br/><span class="email">' + item.fields.email + '</span><br/><span class="url">' + item.fields.url + '</span><br/>' |
|||
var latLng = new google.maps.LatLng(item.fields.latitude, item.fields.longitude) |
|||
var marker = new google.maps.Marker({ |
|||
position: latLng, |
|||
map: map, |
|||
title: item.fields.name, |
|||
category: item.fields.category, |
|||
tags: item.fields.sub_categories, |
|||
}) |
|||
google.maps.event.addListener(marker, "click", function () { |
|||
infowindow.content = content |
|||
infowindow.open(map, marker); |
|||
}); |
|||
gmap_markers.push(marker) |
|||
|
|||
if ($.inArray(item.fields.category, categories) == -1) { |
|||
categories.push(item.fields.category) |
|||
} |
|||
$.each(item.fields.sub_categories, function (key, item) { |
|||
if ($.inArray(item, tags) == -1) { |
|||
tags.push(item) |
|||
} |
|||
}) |
|||
}) |
|||
$.each(categories, function (key, category) { |
|||
var $button = $(' <a href="#category_' + category + '">' + category + '</a> ').bind('click', function () { |
|||
toggleCategory(category) |
|||
}) |
|||
$('#gmap_categories').append($button) |
|||
}) |
|||
|
|||
$.each(tags, function (key, tag) { |
|||
var $button = $(' <a href="#tag_' + tag + '">' + tag + '</a> ').bind('click', function () { |
|||
toggleTag(tag) |
|||
}) |
|||
$('#gmap_sub_categories').append($button) |
|||
}) |
|||
}) |
|||
google.maps.event.addListener(map, 'click', function () { |
|||
if (open_marker != '') { |
|||
open_marker.close(); |
|||
} |
|||
open_marker = ''; |
|||
}); |
|||
|
|||
}) |
|||
2116
static/js/jquery-2.2.4.min.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
3414
static/js/moment-with-locales.min.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,40 +1,27 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from datetime import datetime, timedelta |
|||
|
|||
from django import forms |
|||
from models import Task |
|||
|
|||
from models import TASK_PRIORITIES, TASK_STATES |
|||
from accounts_app.models import UserProfile |
|||
from devapp.models import Device |
|||
|
|||
class TaskFrm(forms.ModelForm): |
|||
|
|||
class TaskFrm(forms.Form): |
|||
descr = forms.CharField(max_length=128, required=True, widget=forms.TextInput(attrs={ |
|||
'placeholder': u'Краткое описание', |
|||
'class': "form-control", |
|||
'required':'' |
|||
})) |
|||
recipient = forms.ModelChoiceField( |
|||
queryset=UserProfile.objects.all(), |
|||
widget=forms.Select(attrs={'class': 'form-control', 'required':''}) |
|||
) |
|||
device = forms.ModelChoiceField( |
|||
queryset=Device.objects.all(), |
|||
widget=forms.Select(attrs={'class': 'form-control', 'required':''}) |
|||
) |
|||
priority = forms.ChoiceField( |
|||
choices=TASK_PRIORITIES, |
|||
widget=forms.Select(attrs={'class': 'form-control'}), |
|||
required=False, |
|||
initial=TASK_PRIORITIES[2][0] |
|||
) |
|||
state = forms.ChoiceField( |
|||
choices=TASK_STATES, |
|||
widget=forms.Select(attrs={'class': 'form-control'}), |
|||
required=False, |
|||
initial=TASK_PRIORITIES[0][0] |
|||
) |
|||
out_date = forms.DateField( |
|||
widget=forms.DateInput(attrs={'class': 'form-control',}), |
|||
initial=datetime.now()+timedelta(days=7) |
|||
) |
|||
class Meta: |
|||
model = Task |
|||
exclude = ['time_of_create', 'author'] |
|||
widgets = { |
|||
'descr': forms.TextInput(attrs={ |
|||
'placeholder': u'Краткое описание', |
|||
'class': "form-control", |
|||
'required': '' |
|||
}), |
|||
'recipient': forms.Select(attrs={'class': 'form-control', 'required':''}), |
|||
'device': forms.Select(attrs={'class': 'form-control', 'required':''}), |
|||
'priority': forms.Select(attrs={'class': 'form-control'}), |
|||
'state': forms.Select(attrs={'class': 'form-control'}), |
|||
'out_date': forms.DateInput(attrs={'class': 'form-control'}), |
|||
'attachment': forms.FileInput(attrs={'class': 'form-control'}) |
|||
} |
|||
initials = { |
|||
'out_date': datetime.now()+timedelta(days=7) |
|||
} |
|||
@ -1,75 +1,81 @@ |
|||
{% extends request.is_ajax|yesno:'bajax.html,base.html' %} |
|||
{% block main %} |
|||
|
|||
<ol class="breadcrumb"> |
|||
<li><span class="glyphicon glyphicon-home"></span></li> |
|||
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li> |
|||
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li> |
|||
<li class="active">Добавить абонента</li> |
|||
</ol> |
|||
<ol class="breadcrumb"> |
|||
<li><span class="glyphicon glyphicon-home"></span></li> |
|||
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li> |
|||
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li> |
|||
<li class="active">Добавить абонента</li> |
|||
</ol> |
|||
|
|||
|
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading"> |
|||
<h3 class="panel-title">Добавьте аккаунт абонента</h3> |
|||
</div> |
|||
<div class="panel-body"> |
|||
{% if warntext %} |
|||
<div class="alert-danger">{{ warntext }}</div> |
|||
{% endif %} |
|||
<form role="form" action="{% url 'addabon_link' abon_group.id %}" method="post">{% csrf_token %} |
|||
<div class="form-group"> |
|||
<label for="login">Логин абонента</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> |
|||
{{ form.username }}{{ form.username.errors }} |
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading"> |
|||
<h3 class="panel-title">Добавьте аккаунт абонента</h3> |
|||
</div> |
|||
<div class="panel-body"> |
|||
{% if warntext %} |
|||
<div class="alert-danger">{{ warntext }}</div> |
|||
{% endif %} |
|||
<form role="form" action="{% url 'addabon_link' abon_group.id %}" method="post">{% csrf_token %} |
|||
<div class="form-group"> |
|||
<label for="login">Логин абонента</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> |
|||
{{ form.username }}{{ form.username.errors }} |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="fio">Фамилия Имя</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-bookmark"></span></span> |
|||
{{ form.fio }}{{ form.fio.errors }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="fio">Фамилия Имя</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-bookmark"></span></span> |
|||
{{ form.fio }}{{ form.fio.errors }} |
|||
<div class="form-group"> |
|||
<label for="ip">IP Адрес</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-ice-lolly"></span></span> |
|||
{{ form.ip_address }}{{ form.ip_address.errors }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="ip">IP Адрес</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-ice-lolly"></span></span> |
|||
{{ form.ip_address }}{{ form.ip_address.errors }} |
|||
<div class="form-group"> |
|||
<label for="telephone">Телефон</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-phone"></span></span> |
|||
{{ form.telephone }}{{ form.telephone.errors }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="telephone">Телефон</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-phone"></span></span> |
|||
{{ form.telephone }}{{ form.telephone.errors }} |
|||
<div class="form-group"> |
|||
<label for="grp">Группа абонентов</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-grain"></span></span> |
|||
{{ form.group }}{{ form.group.errors }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="grp">Группа абонентов</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-grain"></span></span> |
|||
{{ form.group }}{{ form.group.errors }} |
|||
<div class="form-group"> |
|||
<label for="address">Адрес проживания</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-map-marker"></span></span> |
|||
{{ form.address }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="address">Адрес проживания</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-map-marker"></span></span> |
|||
{{ form.address }} |
|||
<div class="btn-group"> |
|||
<button type="submit" class="btn btn-sm btn-primary"> |
|||
<span class="glyphicon glyphicon-save"></span> Сохранить |
|||
</button> |
|||
<button type="reset" class="btn btn-sm btn-default"> |
|||
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<div class="btn-group"> |
|||
<button type="submit" class="btn btn-sm btn-primary"> |
|||
<span class="glyphicon glyphicon-save"></span> Сохранить |
|||
</button> |
|||
<button type="reset" class="btn btn-sm btn-default"> |
|||
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить |
|||
</button> |
|||
</div> |
|||
</form> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
{% endblock %} |
|||
@ -1,50 +1,54 @@ |
|||
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} |
|||
{% block content %} |
|||
|
|||
<table class="table table-striped table-bordered"> |
|||
<thead> |
|||
<tr> |
|||
<th>Статус</th> |
|||
<th>Месяц</th> |
|||
<th>Стоимость</th> |
|||
<th>Комментарий</th> |
|||
<th>Дата создания</th> |
|||
<th>Дата оплаты</th> |
|||
<th>Назначил</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for inv in invoices %} |
|||
<tr> |
|||
<td>{% if inv.status %} |
|||
<span class="glyphicon glyphicon-ok"></span> |
|||
{% else %} |
|||
<span class="glyphicon glyphicon-time"></span> |
|||
{% endif %}</td> |
|||
<td>{{ inv.date_create|date:"F" }}</td> |
|||
<td>{{ inv.amount }}</td> |
|||
<td>{{ inv.comment }}</td> |
|||
<td>{{ inv.date_create|date:"D d E Y H:i:s" }}</td> |
|||
<td> |
|||
{% if inv.date_pay %} |
|||
{{ inv.date_pay|date:"D d M Y H:i:s" }} |
|||
{% else %} |
|||
{{ inv.status|yesno:'Создан оплаченным,Ещё не оплачено' }} |
|||
{% endif %} |
|||
</td> |
|||
<td><a href="{% url 'other_profile' inv.author.id %}" target="_blank">{{ inv.author.username }}</a></td> |
|||
</tr> |
|||
{% empty %} |
|||
<tr><td colspan="7">Назначенные платежи отсутствуют</td></tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
<tfoot> |
|||
<tr><th colspan="7"> |
|||
<a href="{% url 'abonapp_addinvoice_link' abon_group.id abon.id %}" class="btn btn-success btn-sm"> |
|||
<span class="glyphicon glyphicon-plus"></span> Добавить |
|||
</a> |
|||
</th></tr> |
|||
</tfoot> |
|||
</table> |
|||
<table class="table table-striped table-bordered"> |
|||
<thead> |
|||
<tr> |
|||
<th>Статус</th> |
|||
<th>Месяц</th> |
|||
<th>Стоимость</th> |
|||
<th>Комментарий</th> |
|||
<th>Дата создания</th> |
|||
<th>Дата оплаты</th> |
|||
<th>Назначил</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for inv in invoices %} |
|||
<tr> |
|||
<td>{% if inv.status %} |
|||
<span class="glyphicon glyphicon-ok"></span> |
|||
{% else %} |
|||
<span class="glyphicon glyphicon-time"></span> |
|||
{% endif %}</td> |
|||
<td>{{ inv.date_create|date:"F" }}</td> |
|||
<td>{{ inv.amount }}</td> |
|||
<td>{{ inv.comment }}</td> |
|||
<td>{{ inv.date_create|date:"D d E Y H:i:s" }}</td> |
|||
<td> |
|||
{% if inv.date_pay %} |
|||
{{ inv.date_pay|date:"D d M Y H:i:s" }} |
|||
{% else %} |
|||
{{ inv.status|yesno:'Создан оплаченным,Ещё не оплачено' }} |
|||
{% endif %} |
|||
</td> |
|||
<td><a href="{% url 'other_profile' inv.author.id %}" target="_blank">{{ inv.author.username }}</a></td> |
|||
</tr> |
|||
{% empty %} |
|||
<tr> |
|||
<td colspan="7">Назначенные платежи отсутствуют</td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
<tfoot> |
|||
<tr> |
|||
<th colspan="7"> |
|||
<a href="{% url 'abonapp_addinvoice_link' abon_group.id abon.id %}" class="btn btn-success btn-sm"> |
|||
<span class="glyphicon glyphicon-plus"></span> Добавить |
|||
</a> |
|||
</th> |
|||
</tr> |
|||
</tfoot> |
|||
</table> |
|||
|
|||
{% endblock %} |
|||
@ -1,30 +1,33 @@ |
|||
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} |
|||
{% block content %} |
|||
|
|||
<table class="table table-striped table-bordered"> |
|||
<thead> |
|||
<tr> |
|||
<th>Абонент</th> |
|||
<th>Сумма</th> |
|||
<th>Дата транзакции</th> |
|||
<th>Автор платежа</th> |
|||
<th>Комментарий</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for ph in pay_history %}<tr> |
|||
<td><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ ph.abon.username }}</a></td> |
|||
<td>{{ ph.amount }}</td> |
|||
<td>{{ ph.date|date:'d F Y, H:i:s' }}</td> |
|||
<td><a target="_blank" href="{% url 'other_profile' ph.author.id %}">{{ ph.author.username }}</a></td> |
|||
<td>{{ ph.comment }}</td> |
|||
</tr> |
|||
{% empty %} |
|||
<tr><td colspan="5">История платежей пуста</td></tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
<table class="table table-striped table-bordered"> |
|||
<thead> |
|||
<tr> |
|||
<th>Абонент</th> |
|||
<th>Сумма</th> |
|||
<th>Дата транзакции</th> |
|||
<th>Автор платежа</th> |
|||
<th>Комментарий</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for ph in pay_history %} |
|||
<tr> |
|||
<td><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ ph.abon.username }}</a></td> |
|||
<td>{{ ph.amount }}</td> |
|||
<td>{{ ph.date|date:'d F Y, H:i:s' }}</td> |
|||
<td><a target="_blank" href="{% url 'other_profile' ph.author.id %}">{{ ph.author.username }}</a></td> |
|||
<td>{{ ph.comment }}</td> |
|||
</tr> |
|||
{% empty %} |
|||
<tr> |
|||
<td colspan="5">История платежей пуста</td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
|
|||
</table> |
|||
</table> |
|||
|
|||
{% include 'toolbar_page.html' with pag=pay_history %} |
|||
{% include 'toolbar_page.html' with pag=pay_history %} |
|||
{% endblock %} |
|||
@ -1,68 +1,79 @@ |
|||
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} |
|||
{% block content %} |
|||
|
|||
<legend>Купленные абонентом услуги (назначенные тарифные планы)</legend> |
|||
<table class="table table-striped table-bordered"> |
|||
<thead> |
|||
<tr> |
|||
<th width="50">Приоритет</th> |
|||
<th>Тариф</th> |
|||
<th>Стоимость</th> |
|||
<th>Входящая скорость</th> |
|||
<th>Исходящая скорость</th> |
|||
<th>Время действия</th> |
|||
<th>Ред.</th> |
|||
</tr> |
|||
</thead> |
|||
<legend>Купленные абонентом услуги (назначенные тарифные планы)</legend> |
|||
<table class="table table-striped table-bordered"> |
|||
<thead> |
|||
<tr> |
|||
<th width="50">Приоритет</th> |
|||
<th>Тариф</th> |
|||
<th>Стоимость</th> |
|||
<th>Входящая скорость</th> |
|||
<th>Исходящая скорость</th> |
|||
<th>Время действия</th> |
|||
<th>Ред.</th> |
|||
</tr> |
|||
</thead> |
|||
|
|||
<tbody> |
|||
{% for trf in abon_tarifs %} |
|||
<tr{% if trf.id == active_abontariff_id %} class="active"{% endif %}> |
|||
<td>{{ trf.tariff_priority }}</td> |
|||
<td><a href="{% url 'tarifs_edit_link' trf.tariff.id %}" title="{{ trf.time_start|default:'' }}">{{ trf.tariff.title }}</a></td> |
|||
<td>{{ trf.tariff.amount }}</td> |
|||
<td>{{ trf.tariff.speedIn }}</td> |
|||
<td>{{ trf.tariff.speedOut }}</td> |
|||
<td>{{ trf.tariff.time_of_action }}</td> |
|||
{% if trf.id != active_abontariff_id %} |
|||
<td class="btn-group"> |
|||
{% if not active_abontariff_id %} |
|||
<a href="{% url 'abonapp_activate_service' abon_group.id abon.id trf.id %}" class="btn btn-success btn-sm" title="Активировать услугу"> |
|||
<i class="glyphicon glyphicon-shopping-cart"></i> |
|||
</a> |
|||
<tbody> |
|||
{% for trf in abon_tarifs %} |
|||
<tr{% if trf.id == active_abontariff_id %} class="active"{% endif %}> |
|||
<td>{{ trf.tariff_priority }}</td> |
|||
<td><a href="{% url 'tarifs_edit_link' trf.tariff.id %}" |
|||
title="{{ trf.time_start|default:'' }}">{{ trf.tariff.title }}</a></td> |
|||
<td>{{ trf.tariff.amount }}</td> |
|||
<td>{{ trf.tariff.speedIn }}</td> |
|||
<td>{{ trf.tariff.speedOut }}</td> |
|||
<td>{{ trf.tariff.time_of_action }}</td> |
|||
{% if trf.id != active_abontariff_id %} |
|||
<td class="btn-group"> |
|||
{% if not active_abontariff_id %} |
|||
<a href="{% url 'abonapp_activate_service' abon_group.id abon.id trf.id %}" |
|||
class="btn btn-success btn-sm" title="Активировать услугу"> |
|||
<i class="glyphicon glyphicon-shopping-cart"></i> |
|||
</a> |
|||
{% endif %} |
|||
<a href="{% url 'abonapp_chpriority_tariff' abon_group.id abon.id %}?t={{ trf.id }}&a=up" |
|||
class="btn btn-default btn-sm" title="Повысить приоритет"> |
|||
<i class="glyphicon glyphicon-hand-up"></i> |
|||
</a> |
|||
<a href="{% url 'abonapp_chpriority_tariff' abon_group.id abon.id %}?t={{ trf.id }}&a=down" |
|||
class="btn btn-default btn-sm" title="Понизить приоритет"> |
|||
<i class="glyphicon glyphicon-hand-down"></i> |
|||
</a> |
|||
<a href="{% url 'abonapp_unsubscribe_service' abon_group.id abon.id trf.id %}" |
|||
class="btn btn-danger btn-sm" title="Удалить услугу"> |
|||
<i class="glyphicon glyphicon-remove"></i> |
|||
</a> |
|||
</td> |
|||
{% else %} |
|||
<td> |
|||
<a href="{% url 'abonapp_compl_srv' abon_group.id abon.id trf.id %}" |
|||
title="Завершить услугу досрочно" class="btn btn-danger btn-sm"> |
|||
<i class="glyphicon glyphicon-remove"></i> Завершить |
|||
</a> |
|||
</td> |
|||
{% endif %} |
|||
<a href="{% url 'abonapp_chpriority_tariff' abon_group.id abon.id %}?t={{ trf.id }}&a=up" class="btn btn-default btn-sm" title="Повысить приоритет"> |
|||
<i class="glyphicon glyphicon-hand-up"></i> |
|||
</a> |
|||
<a href="{% url 'abonapp_chpriority_tariff' abon_group.id abon.id %}?t={{ trf.id }}&a=down" class="btn btn-default btn-sm" title="Понизить приоритет"> |
|||
<i class="glyphicon glyphicon-hand-down"></i> |
|||
</a> |
|||
<a href="{% url 'abonapp_unsubscribe_service' abon_group.id abon.id trf.id %}" class="btn btn-danger btn-sm" title="Удалить услугу"> |
|||
<i class="glyphicon glyphicon-remove"></i> |
|||
</a> |
|||
</td> |
|||
{% else %} |
|||
<td> |
|||
<a href="{% url 'abonapp_compl_srv' abon_group.id abon.id trf.id %}" title="Завершить услугу досрочно" class="btn btn-danger btn-sm"> |
|||
<i class="glyphicon glyphicon-remove"></i> Завершить |
|||
</a> |
|||
</td> |
|||
{% endif %} |
|||
</tr> |
|||
{% empty %} |
|||
<tr><td colspan="7">Нет подключённых абоненту услуг, <a href="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" class="lgtbx">купить</a></td></tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
</tr> |
|||
{% empty %} |
|||
<tr> |
|||
<td colspan="7">Нет подключённых абоненту услуг, <a |
|||
href="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" class="lgtbx">купить</a></td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
|
|||
<tfoot> |
|||
<tr><th colspan="7"> |
|||
<a href="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" class="btn btn-sm btn-success"> |
|||
<span class="glyphicon glyphicon-plus"></span> Купить услугу |
|||
</a> |
|||
</th></tr> |
|||
</tfoot> |
|||
<tfoot> |
|||
<tr> |
|||
<th colspan="7"> |
|||
<a href="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" class="btn btn-sm btn-success"> |
|||
<span class="glyphicon glyphicon-plus"></span> Купить услугу |
|||
</a> |
|||
</th> |
|||
</tr> |
|||
</tfoot> |
|||
|
|||
</table> |
|||
</table> |
|||
|
|||
|
|||
{% endblock %} |
|||
@ -1,67 +1,72 @@ |
|||
{% extends 'base.html' %} |
|||
{% block main %} |
|||
|
|||
<ol class="breadcrumb"> |
|||
<li><span class="glyphicon glyphicon-home"></span></li> |
|||
<li class="active">Администраторы</li> |
|||
</ol> |
|||
<ol class="breadcrumb"> |
|||
<li><span class="glyphicon glyphicon-home"></span></li> |
|||
<li class="active">Администраторы</li> |
|||
</ol> |
|||
|
|||
|
|||
<h3>Список аккаунтов администраторов</h3> |
|||
<div class="table-responsive"> |
|||
<table class="table table-striped table-bordered"> |
|||
<thead> |
|||
<tr> |
|||
<th class="col-sm-1">Фото</th> |
|||
<th>Ник</th> |
|||
<th>ФИО (или ник если нет)</th> |
|||
<th class="col-sm-2">Телефон</th> |
|||
<th class="col-sm-2">Skype</th> |
|||
<th width="150">—</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for usr in users %} |
|||
<h3>Список аккаунтов администраторов</h3> |
|||
<div class="table-responsive"> |
|||
<table class="table table-striped table-bordered"> |
|||
<thead> |
|||
<tr> |
|||
<td><a href="{% url 'other_profile' usr.id %}"> |
|||
<img width="50" src="{{ usr.avatar.min|default:"/static/img/user_ava.gif" }}" alt="{{ usr.username }}"/> |
|||
</a></td> |
|||
<td><a href="{% url 'other_profile' usr.id %}">{{ usr.username }}</a></td> |
|||
<td>{{ usr.get_full_name }}</td> |
|||
<td>{% if usr.telephone %}<a href="tel:{{ usr.telephone }}">{{ usr.telephone }}</a>{% else %}Нету{% endif %}</td> |
|||
<td>{% if usr.skype %}<a href="skype:{{ usr.skype }}?call">{{ usr.skype }}{% else %}Нету{% endif %}</a></td> |
|||
<td class="btn-group"> |
|||
<a href="{% url 'profile_appoint_task' usr.id %}" class="btn btn-sm btn-default" title="Дать задание"> |
|||
<span class="glyphicon glyphicon-tasks"></span> |
|||
</a> |
|||
<a href="{% url 'privmsg_send_message' %}?a={{ usr.id }}" class="btn btn-sm btn-info" title="Отправить сообщение"> |
|||
<span class="glyphicon glyphicon-envelope"></span> |
|||
</a> |
|||
<a href="#" class="btn btn-sm btn-danger"> |
|||
<span class="glyphicon glyphicon-remove"></span> |
|||
</a> |
|||
</td> |
|||
<th class="col-sm-1">Фото</th> |
|||
<th>Ник</th> |
|||
<th>ФИО (или ник если нет)</th> |
|||
<th class="col-sm-2">Телефон</th> |
|||
<th class="col-sm-2">Skype</th> |
|||
<th width="150">—</th> |
|||
</tr> |
|||
{% empty %} |
|||
<tr> |
|||
<td colspan="6"><b>Нет пользователей</b></td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
{% if request.user.is_superuser %} |
|||
<tfoot> |
|||
<tr> |
|||
<th colspan="6"> |
|||
<a href="{% url 'create_profile_link' %}" class="btn btn-default" title="Добавить аккаунт"> |
|||
<span class="glyphicon glyphicon-plus-sign"></span> |
|||
</a> |
|||
</th> |
|||
</tr> |
|||
</tfoot> |
|||
{% endif %} |
|||
</table> |
|||
</div> |
|||
</thead> |
|||
<tbody> |
|||
{% for usr in users %} |
|||
<tr> |
|||
<td><a href="{% url 'other_profile' usr.id %}"> |
|||
<img width="50" src="{{ usr.avatar.min|default:"/static/img/user_ava.gif" }}" |
|||
alt="{{ usr.username }}"/> |
|||
</a></td> |
|||
<td><a href="{% url 'other_profile' usr.id %}">{{ usr.username }}</a></td> |
|||
<td>{{ usr.get_full_name }}</td> |
|||
<td>{% if usr.telephone %}<a href="tel:{{ usr.telephone }}">{{ usr.telephone }}</a>{% else %} |
|||
Нету{% endif %}</td> |
|||
<td>{% if usr.skype %}<a href="skype:{{ usr.skype }}?call">{{ usr.skype }}{% else %} |
|||
Нету{% endif %}</a></td> |
|||
<td class="btn-group"> |
|||
<a href="{% url 'profile_appoint_task' usr.id %}" class="btn btn-sm btn-default" |
|||
title="Дать задание"> |
|||
<span class="glyphicon glyphicon-tasks"></span> |
|||
</a> |
|||
<a href="{% url 'privmsg_send_message' %}?a={{ usr.id }}" class="btn btn-sm btn-info" |
|||
title="Отправить сообщение"> |
|||
<span class="glyphicon glyphicon-envelope"></span> |
|||
</a> |
|||
<a href="#" class="btn btn-sm btn-danger"> |
|||
<span class="glyphicon glyphicon-remove"></span> |
|||
</a> |
|||
</td> |
|||
</tr> |
|||
{% empty %} |
|||
<tr> |
|||
<td colspan="6"><b>Нет пользователей</b></td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
{% if request.user.is_superuser %} |
|||
<tfoot> |
|||
<tr> |
|||
<th colspan="6"> |
|||
<a href="{% url 'create_profile_link' %}" class="btn btn-default" title="Добавить аккаунт"> |
|||
<span class="glyphicon glyphicon-plus-sign"></span> |
|||
</a> |
|||
</th> |
|||
</tr> |
|||
</tfoot> |
|||
{% endif %} |
|||
</table> |
|||
</div> |
|||
|
|||
{% include 'toolbar_page.html' with pag=users %} |
|||
{% include 'toolbar_page.html' with pag=users %} |
|||
|
|||
{% endblock %} |
|||
@ -1,93 +1,111 @@ |
|||
{% extends request.is_ajax|yesno:'bajax.html,base.html' %} |
|||
{% block main %} |
|||
|
|||
<ol class="breadcrumb"> |
|||
<li><span class="glyphicon glyphicon-home"></span></li> |
|||
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li> |
|||
<li class="active">Добавить</li> |
|||
</ol> |
|||
<ol class="breadcrumb"> |
|||
<li><span class="glyphicon glyphicon-home"></span></li> |
|||
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li> |
|||
<li class="active">Добавить</li> |
|||
</ol> |
|||
|
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading"> |
|||
<h3 class="panel-title">Создайте новый аккаунт</h3> |
|||
</div> |
|||
<div class="panel-body"> |
|||
<div class="row"> |
|||
<div class="col-sm-3"> |
|||
<div class="thumbnail"> |
|||
<img alt="Avatar" src="/static/img/user_ava.gif"/> |
|||
<div class="caption"> |
|||
<input type="file" name="avatar"/> |
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading"> |
|||
<h3 class="panel-title">Создайте новый аккаунт</h3> |
|||
</div> |
|||
<div class="panel-body"> |
|||
<div class="row"> |
|||
<div class="col-sm-3"> |
|||
<div class="thumbnail"> |
|||
<img alt="Avatar" src="/static/img/user_ava.gif"/> |
|||
|
|||
<div class="caption"> |
|||
<input type="file" name="avatar"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-9"> |
|||
{% if warntext %} |
|||
<div class="alert-info">{{ warntext }}</div> |
|||
{% endif %} |
|||
<div class="col-sm-9"> |
|||
{% if warntext %} |
|||
<div class="alert-info">{{ warntext }}</div> |
|||
{% endif %} |
|||
|
|||
<form role="form" action="{% url 'create_profile_link' %}" method="post">{% csrf_token %} |
|||
<div class="form-group"> |
|||
<label for="login">Логин</label> |
|||
|
|||
<form role="form" action="{% url 'create_profile_link' %}" method="post">{% csrf_token %} |
|||
<div class="form-group"> |
|||
<label for="login">Логин</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> |
|||
<input id="login" type="text" name="username" placeholder="Имя пользователя" required value="{{ newuser.username }}" class="form-control"> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> |
|||
<input id="login" type="text" name="username" placeholder="Имя пользователя" required |
|||
value="{{ newuser.username }}" class="form-control"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="fio">Фамилия Имя</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-folder-close"></span></span> |
|||
<input id="fio" type="text" name="fio" placeholder="ФИО" value="{{ newuser.fio }}" class="form-control"> |
|||
<div class="form-group"> |
|||
<label for="fio">Фамилия Имя</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span |
|||
class="glyphicon glyphicon-folder-close"></span></span> |
|||
<input id="fio" type="text" name="fio" placeholder="ФИО" value="{{ newuser.fio }}" |
|||
class="form-control"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="mail">Почта</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span></span> |
|||
<input id='mail' type="text" name="email" placeholder="Email" value="{{ newuser.email }}" class="form-control"> |
|||
<div class="form-group"> |
|||
<label for="mail">Почта</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span |
|||
class="glyphicon glyphicon-envelope"></span></span> |
|||
<input id='mail' type="text" name="email" placeholder="Email" |
|||
value="{{ newuser.email }}" class="form-control"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="tel">Телефон</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-phone"></span></span> |
|||
<input id="tel" type="tel" pattern="\+[7,8,9,3]\d{10,11}" name="telephone" placeholder="+[7,8,9,3] и 10,11 цифр" value="{{ newuser.telephone }}" class="form-control" required> |
|||
<div class="form-group"> |
|||
<label for="tel">Телефон</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-phone"></span></span> |
|||
<input id="tel" type="tel" pattern="\+[7,8,9,3]\d{10,11}" name="telephone" |
|||
placeholder="+[7,8,9,3] и 10,11 цифр" value="{{ newuser.telephone }}" |
|||
class="form-control" required> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="skype"><a title="Что это" target="_blank" href="http://lurkmore.to/Skype">Skype</a></label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-earphone"></span></span> |
|||
<input id="skype" type="text" value="{{ newuser.skype }}" name="skype" placeholder="Skype" class="form-control"> |
|||
<div class="form-group"> |
|||
<label for="skype"><a title="Что это" target="_blank" |
|||
href="http://lurkmore.to/Skype">Skype</a></label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span |
|||
class="glyphicon glyphicon-earphone"></span></span> |
|||
<input id="skype" type="text" value="{{ newuser.skype }}" name="skype" |
|||
placeholder="Skype" class="form-control"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="passw1">Введите пароль</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span> |
|||
<input id="passw1" type="password" name="passwd" required class="form-control"> |
|||
<div class="form-group"> |
|||
<label for="passw1">Введите пароль</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span> |
|||
<input id="passw1" type="password" name="passwd" required class="form-control"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="passw2">Повторите пароль</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span> |
|||
<input id="passw2" type="password" name="conpasswd" required class="form-control"> |
|||
<div class="form-group"> |
|||
<label for="passw2">Повторите пароль</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span> |
|||
<input id="passw2" type="password" name="conpasswd" required class="form-control"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="btn-group"> |
|||
<button type="submit" class="btn btn-primary"> |
|||
<span class="glyphicon glyphicon-floppy-disk"></span> Сохранить |
|||
</button> |
|||
<button type="reset" class="btn btn-default"> |
|||
<span class="glyphicon glyphicon-remove"></span> Сбросить |
|||
</button> |
|||
</div> |
|||
</form> |
|||
<div class="btn-group"> |
|||
<button type="submit" class="btn btn-primary"> |
|||
<span class="glyphicon glyphicon-floppy-disk"></span> Сохранить |
|||
</button> |
|||
<button type="reset" class="btn btn-default"> |
|||
<span class="glyphicon glyphicon-remove"></span> Сбросить |
|||
</button> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
{% endblock %} |
|||
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue