concerto: initial commit
This commit is contained in:
parent
5ad5d3424c
commit
a76c23c990
|
@ -0,0 +1,20 @@
|
|||
Provides webservices to a "Concerto"-like database
|
||||
|
||||
icon-concerto.svg license
|
||||
=========================
|
||||
|
||||
Creative Commons – Attribution (CC BY 3.0) http://creativecommons.org/licenses/by/3.0/us/
|
||||
|
||||
Family designed by Ahmed Elzahra http://www.thenounproject.com/trochilidae
|
||||
from the Noun Project http://www.thenounproject.com
|
||||
|
||||
original license.txt :
|
||||
|
||||
Thank you for using The Noun Project. This icon is licensed under Creative
|
||||
Commons Attribution and must be attributed as:
|
||||
|
||||
Family by Ahmed Trochilidae from The Noun Project
|
||||
|
||||
If you have a Premium Account or have purchased a license for this icon, you
|
||||
don't need to worry about attribution! We will share the profits from your
|
||||
purchase with this icon's designer.
|
|
@ -0,0 +1,9 @@
|
|||
from django.contrib import admin
|
||||
from models import Concerto
|
||||
|
||||
class ConcertoAdmin(admin.ModelAdmin):
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
list_display = ('title', 'slug',)
|
||||
|
||||
admin.site.register(Concerto, ConcertoAdmin)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
from django.utils.text import slugify
|
||||
from django import forms
|
||||
|
||||
from .models import Concerto
|
||||
|
||||
class ConcertoForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Concerto
|
||||
exclude = ('slug', 'users')
|
||||
|
||||
def save(self, commit=True):
|
||||
if not self.instance.slug:
|
||||
self.instance.slug = slugify(self.instance.title)
|
||||
return super(ConcertoForm, self).save(commit=commit)
|
|
@ -0,0 +1,25 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||
<g id="Layer_1_1_">
|
||||
</g>
|
||||
<path d="M64.63,56.39c-0.84,0.79-1.47,1.32-1.47,1.61v26.5c0,1.45-1.18,2.62-2.62,2.62h-5.55c-0.91,0-1.79-0.4-2.391-0.93 c-0.479-0.41-0.77-0.91-0.77-1.36v-3c0-0.39-0.13-0.76-0.34-1.061C51.16,80.3,50.61,80,49.99,80s-1.16,0.3-1.49,0.77 c-0.21,0.301-0.34,0.671-0.34,1.061v3c0,1.02-0.62,2.29-2.19,2.29h-7.43c-1.45,0-2.63-1.17-2.63-2.62V58 c0-1.26-11.15-7.13-0.26-18.9c1.32-1.44,2.98-2.96,5.02-4.58c0.48-0.37-0.06-0.61,0.99,0c0.62,0.37,1.46,0.76,2.53,1.09 c1.1,0.34,2.46,0.61,4.1,0.72c0.47,0.03,0.97,0.05,1.49,0.05c0.51,0,0.98-0.02,1.43-0.05h0.07c0.319-0.02,0.62-0.05,0.92-0.09 c2.68-0.29,4.45-1.04,5.53-1.71c1.02-0.61,0.489-0.38,0.989,0c0.49,0.37,0.95,0.74,1.391,1.1c1.449,1.17,2.68,2.3,3.72,3.38 c1.439,1.5,2.5,2.9,3.25,4.21C70.95,49.89,66.98,54.17,64.63,56.39z"/>
|
||||
<path d="M62.161,94.438c0,1.062-2.1,1.188-4.688,1.188l0,0c-2.59,0-4.688-0.216-4.688-1.188v-0.125c0-2.588,2.099-4.688,4.688-4.688 l0,0c2.588,0,4.688,2.1,4.688,4.688V94.438z"/>
|
||||
<path d="M46.8,94.438c0,1.062-2.099,1.188-4.688,1.188l0,0c-2.589,0-4.688-0.216-4.688-1.188v-0.125 c0-2.588,2.099-4.688,4.688-4.688l0,0c2.589,0,4.688,2.1,4.688,4.688V94.438z"/>
|
||||
<circle cx="49.546" cy="19.25" r="14.125"/>
|
||||
<g id="Layer_1_2_">
|
||||
</g>
|
||||
<g id="Layer_1_3_">
|
||||
</g>
|
||||
<path d="M30.057,57.234v2.038h-19.7v-3.113c0-1.067-10.896-6.646,4.617-18.179c0,0,1.906,2.212,7.1,2.212 c5.212,0,6.935-2.212,6.935-2.212c0.725,0.516,1.39,1.023,2.002,1.513C19.546,50.598,30.057,56.09,30.057,57.234z"/>
|
||||
<path d="M10.356,61.481h19.7v10.942H25.93c-1.207,0-2.335-0.944-2.335-1.697v-2.211c0-0.744-0.612-1.356-1.364-1.356 c-0.743,0-1.347,0.612-1.347,1.356v2.211c0,0.753-0.464,1.697-1.618,1.697h-6.969c-1.067,0-1.941-0.866-1.941-1.933V61.481z"/>
|
||||
<path d="M30.345,82.979v0.096c0,0.787-1.547,0.874-3.462,0.874c-0.953,0-1.828-0.044-2.448-0.166 c-0.63-0.131-1.015-0.35-1.015-0.708v-0.096c0-1.907,1.548-3.463,3.463-3.463c0.883,0,1.696,0.332,2.299,0.874 c0.053,0.044,0.105,0.096,0.149,0.14c0.49,0.49,0.831,1.119,0.953,1.828C30.328,82.558,30.345,82.769,30.345,82.979z"/>
|
||||
<path d="M19.001,83.072c0,0.784-1.551,0.878-3.462,0.878l0,0c-1.913,0-3.462-0.16-3.462-0.878v-0.093 c0-1.911,1.55-3.462,3.462-3.462l0,0c1.911,0,3.462,1.551,3.462,3.462V83.072z"/>
|
||||
<path d="M30.359,23.425H13.623c1.741-2.796,4.842-4.661,8.372-4.661S28.619,20.629,30.359,23.425z"/>
|
||||
<path d="M31.835,28.605c0,5.436-4.413,9.84-9.84,9.84c-5.436,0-9.84-4.405-9.84-9.84c0-1.114,0.19-2.194,0.528-3.192h18.616 C31.646,26.411,31.835,27.491,31.835,28.605z"/>
|
||||
<path d="M60.59,77.42l2.57-8.189v9.359C61.74,78.27,60.59,77.86,60.59,77.42z"/>
|
||||
<path d="M95.35,77.42c0,1.07-6.76,1.93-7.81,1.93h-5.56c-0.62,0-2.08-0.85-3.5-0.85c-1.311,0-2.58,0.85-3.131,0.85H68.41 c-0.09,0-0.23-0.01-0.41-0.02V58c0-1.2,10.95-6.63,2.07-17.41c0.319-0.26,0.649-0.51,1-0.77c0,0,1.899,2.21,7.08,2.21 c5.189,0,6.899-2.21,6.899-2.21c16.061,11.49,4.41,17.78,4.41,18.84L95.35,77.42z"/>
|
||||
<path d="M87.257,84.732c0,0.781-1.545,0.873-3.449,0.873l0,0c-1.904,0-3.447-0.158-3.447-0.873v-0.092 c0-1.904,1.543-3.449,3.447-3.449l0,0c1.904,0,3.449,1.545,3.449,3.449V84.732z"/>
|
||||
<path d="M75.956,84.732c0,0.781-1.544,0.873-3.449,0.873l0,0c-1.902,0-3.446-0.158-3.446-0.873v-0.092 c0-1.904,1.544-3.449,3.446-3.449l0,0c1.905,0,3.449,1.545,3.449,3.449V84.732z"/>
|
||||
<circle cx="77.976" cy="29.425" r="10.39"/>
|
||||
<path d="M74.399,26.262c-0.646,0.646-1.695,0.646-2.343,0l-5.67-5.673c-0.646-0.646-0.646-1.695,0-2.341l0,0 c0.646-0.646,1.693-0.646,2.342,0l5.671,5.673C75.045,24.567,75.047,25.616,74.399,26.262L74.399,26.262z"/>
|
||||
<path d="M81.708,26.262c0.646,0.646,1.693,0.646,2.342,0l5.672-5.673c0.646-0.646,0.646-1.695,0-2.341l0,0 c-0.646-0.646-1.694-0.646-2.342,0l-5.672,5.673C81.062,24.567,81.062,25.616,81.708,26.262L81.708,26.262z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
|
@ -0,0 +1,257 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Application emulating Concerto's webservices.
|
||||
'''
|
||||
|
||||
try:
|
||||
import psycopg2
|
||||
import psycopg2.extras
|
||||
except ImportError:
|
||||
psycopg2 = None
|
||||
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import base64
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils.dateformat import format as date_format
|
||||
from django.utils.dateformat import time_format
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from passerelle.datasources.models import BaseDataSource
|
||||
|
||||
|
||||
class Concerto(BaseDataSource):
|
||||
invoice_hash_secret = models.CharField(max_length=80)
|
||||
pg_database = models.CharField(max_length=64)
|
||||
pg_user = models.CharField(max_length=64, null=True, blank=True)
|
||||
pg_password = models.CharField(max_length=64, null=True, blank=True)
|
||||
pg_host = models.CharField(max_length=64, null=True, blank=True)
|
||||
pg_port = models.CharField(max_length=64, null=True, blank=True)
|
||||
|
||||
category = _('Business Process Connectors')
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u'Concerto™')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Concerto, self).__init__(*args, **kwargs)
|
||||
self.pgconn = None
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('concerto-view', kwargs={'slug': self.slug})
|
||||
|
||||
@classmethod
|
||||
def get_add_url(cls):
|
||||
return reverse('concerto-add')
|
||||
|
||||
def get_edit_url(self):
|
||||
return reverse('concerto-edit', kwargs={'slug': self.slug})
|
||||
|
||||
def get_delete_url(self):
|
||||
return reverse('concerto-delete', kwargs={'slug': self.slug})
|
||||
|
||||
@classmethod
|
||||
def get_verbose_name(cls):
|
||||
return cls._meta.verbose_name
|
||||
|
||||
@classmethod
|
||||
def get_icon_class(cls):
|
||||
return 'concerto'
|
||||
|
||||
def get_connection(self, new=False):
|
||||
if psycopg2 is None:
|
||||
raise Http404
|
||||
if new and self.pgconn is not None:
|
||||
self.pgconn.close()
|
||||
self.pgconn = None
|
||||
if self.pgconn is None:
|
||||
args = {'database': self.pg_database}
|
||||
if self.pg_user:
|
||||
args['user'] = self.pg_user
|
||||
args['password'] = self.pg_password
|
||||
if self.pg_host:
|
||||
args['host'] = self.pg_host
|
||||
if self.pg_port:
|
||||
args['port'] = self.pg_port
|
||||
self.pgconn = psycopg2.connect(**args)
|
||||
return self.pgconn
|
||||
|
||||
def execute_query(self, query, **kwargs):
|
||||
conn = self.get_connection()
|
||||
cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
|
||||
cursor.execute(query, kwargs)
|
||||
return cursor
|
||||
|
||||
def get_hash(self, *args):
|
||||
hash = base64.b64encode(hmac.HMAC(
|
||||
key=str(self.invoice_hash_secret),
|
||||
msg='#'.join(map(lambda s: str(s), args)),
|
||||
digestmod=hashlib.sha256).digest(),
|
||||
altchars='AB')
|
||||
return hash[:8]
|
||||
|
||||
def family_link(self, family_id, secret):
|
||||
query = 'SELECT COUNT(id) FROM data_famille \
|
||||
WHERE id = %(family_id)s \
|
||||
AND code_secret = %(secret)s'
|
||||
cursor = self.execute_query(query, family_id=family_id, secret=secret)
|
||||
exists = cursor.fetchone()[0] != 0
|
||||
query = 'SELECT link_date FROM data_liaisonnameidfamille \
|
||||
WHERE famille_id = %(family_id)s'
|
||||
cursor = self.execute_query(query, family_id=family_id)
|
||||
links = [link[0] for link in cursor.fetchall()]
|
||||
return {'exists': exists, 'links': links}
|
||||
|
||||
def family_data(self, nameid, data_filter=None):
|
||||
queries = {
|
||||
'families': "SELECT f.* FROM data_famille AS f \
|
||||
INNER JOIN data_liaisonnameidfamille AS lp \
|
||||
ON f.id = lp.famille_id \
|
||||
WHERE lp.name_id = %(nameid)s",
|
||||
'kids': "SELECT e.* FROM data_enfant AS e \
|
||||
INNER JOIN data_liaisonnameidfamille as lp \
|
||||
ON e.famille_id = lp.famille_id \
|
||||
WHERE lp.name_id = %(nameid)s",
|
||||
'parents': "SELECT f.id as famille_id, p.* FROM data_personne AS p \
|
||||
INNER JOIN data_liaisonparentfamille as lp \
|
||||
ON lp.personne_id = p.id \
|
||||
INNER JOIN data_famille AS f \
|
||||
ON f.id = lp.famille_id \
|
||||
INNER JOIN data_liaisonnameidfamille as lnf \
|
||||
ON lnf.famille_id = f.id \
|
||||
WHERE lnf.name_id = %(nameid)s"
|
||||
}
|
||||
|
||||
data = {}
|
||||
if data_filter and queries.has_key(data_filter):
|
||||
queries = {data_filter: queries[data_filter]}
|
||||
|
||||
for group, query in queries.iteritems():
|
||||
cursor = self.execute_query(queries[group], nameid=nameid)
|
||||
data[group] = [getattr(self, 'format_family_%s' % group)(row) for row in cursor.fetchall()]
|
||||
return data
|
||||
|
||||
def format_family_parents(self, row):
|
||||
data = dict(row)
|
||||
data.update({'text': '{nom} {prenom}'.format(**row)})
|
||||
return data
|
||||
|
||||
def format_family_kids(self, row):
|
||||
data = dict(row)
|
||||
data.update({'text': '{nom} {prenom} - {date_naissance}'.format(**row)})
|
||||
return data
|
||||
|
||||
def format_family_families(self, row):
|
||||
data = dict(row)
|
||||
data.update({'text': u'Dossier numéro {id}'.format(**row)})
|
||||
return data
|
||||
|
||||
def link_to_family(self, nameid, family_id):
|
||||
queries = (
|
||||
'DELETE FROM data_liaisonnameidfamille \
|
||||
WHERE name_id=%(nameid)s',
|
||||
'INSERT INTO data_liaisonnameidfamille(name_id, famille_id, link_date) \
|
||||
VALUES (%(nameid)s, %(famille)s, CURRENT_TIMESTAMP)'
|
||||
)
|
||||
for query in queries:
|
||||
cursor = self.execute_query(query, nameid=nameid, famille=family_id)
|
||||
|
||||
def unlink_from_family(self, nameid):
|
||||
query = 'DELETE FROM data_liaisonnameidfamille \
|
||||
WHERE name_id = %(nameid)s \
|
||||
RETURNING *'
|
||||
cursor = self.execute_query(query, nameid=nameid)
|
||||
return cursor.fetchone()[0]
|
||||
|
||||
def get_invoices(self, query, nameid):
|
||||
invoices = []
|
||||
for row in self.execute_query(query, nameid=nameid).fetchall():
|
||||
data = dict(row)
|
||||
hash = self.get_hash(data['id'], data['date_generation'], data['montant'])
|
||||
data.update({'hash': hash})
|
||||
invoices.append(data)
|
||||
return invoices
|
||||
|
||||
def family_invoices(self, nameid, status):
|
||||
queries = {'all': 'SELECT invoice.*, invoice.montant as amount, \
|
||||
invoice.date_generation as creation_date, \
|
||||
(DATE(invoice.date_limite_paie) < DATE(NOW())) as expired, \
|
||||
invoice.date_limite_paie as expiration_date, \
|
||||
(invoice.paye OR invoice.prelevement_automatique OR \
|
||||
invoice.statut_tipi IS NOT DISTINCT FROM \'PAID\' OR \
|
||||
invoice.solde = 0) as paid, \
|
||||
DATE(invoice.date_reglement) as paid_date \
|
||||
FROM data_facture AS invoice \
|
||||
INNER JOIN data_famille AS family \
|
||||
ON invoice.famille_id = family.id \
|
||||
INNER JOIN data_liaisonnameidfamille AS lp \
|
||||
ON family.id = lp.famille_id \
|
||||
WHERE lp.name_id = %(nameid)s \
|
||||
AND invoice.active = \'true\' \
|
||||
ORDER BY invoice.date_generation DESC',
|
||||
'unpaid': 'SELECT invoice.*, \
|
||||
(DATE(invoice.date_limite_paie) < DATE(NOW())) as expired, \
|
||||
(invoice.paye OR invoice.prelevement_automatique \
|
||||
OR invoice.statut_tipi \
|
||||
IS NOT DISTINCT FROM \'PAID\' \
|
||||
OR invoice.solde = 0) as paid \
|
||||
FROM data_facture AS invoice \
|
||||
INNER JOIN data_famille AS family \
|
||||
ON invoice.famille_id = family.id \
|
||||
INNER JOIN data_liaisonnameidfamille AS lp \
|
||||
ON family.id = lp.famille_id \
|
||||
WHERE lp.name_id = %(nameid)s \
|
||||
AND invoice.paye = \'false\' \
|
||||
AND invoice.active = \'true\' \
|
||||
AND invoice.solde <> 0 \
|
||||
AND invoice.statut_tipi IS DISTINCT FROM \'PAID\' \
|
||||
AND DATE(invoice.date_generation) <= DATE(now()) \
|
||||
AND DATE(invoice.date_limite_paie) >= DATE(NOW()) \
|
||||
ORDER BY invoice.date_generation DESC'
|
||||
}
|
||||
return self.get_invoices(queries[status], nameid)
|
||||
|
||||
def get_invoice(self, invoice_id, invoice_hash):
|
||||
query = 'SELECT data_facture.id as id, \
|
||||
data_facture.solde as amount, \
|
||||
data_facture.date_generation as creation_date, \
|
||||
(DATE(data_facture.date_limite_paie) < DATE(NOW())) as expired, \
|
||||
data_facture.date_limite_paie as expiration_date, \
|
||||
(data_facture.paye OR \
|
||||
data_facture.prelevement_automatique OR \
|
||||
data_facture.statut_tipi IS NOT DISTINCT FROM \'PAID\' OR \
|
||||
data_facture.solde = 0) as paid, \
|
||||
data_facture.date_reponse_tipi as paid_date, \
|
||||
data_facture.date_passage_perception, \
|
||||
data_facture.prelevement_automatique, \
|
||||
data_facture.id as refdet, \
|
||||
data_facture.statut_tipi, \
|
||||
\'REGIE ORLEANS\' as objet, \
|
||||
data_facture.montant as total_amount \
|
||||
FROM data_facture \
|
||||
WHERE data_facture.id = %(invoice_id)s \
|
||||
AND data_facture.active = \'true\''
|
||||
r = self.execute_query(query, invoice_id=invoice_id).fetchone()
|
||||
if invoice_hash == self.get_hash(r['id'], r['creation_date'],
|
||||
r['total_amount']):
|
||||
return dict(r)
|
||||
|
||||
def update_invoice(self, invoice_id, invoice_hash, status):
|
||||
get_query = 'SELECT id, date_generation, montant FROM \
|
||||
data_facture WHERE id = %(invoice_id)s'
|
||||
update_query = 'UPDATE data_facture \
|
||||
SET date_reponse_tipi=now(), statut_tipi=%(status) \
|
||||
WHERE id = %(invoice_id)s \
|
||||
RETURNING id, paye'
|
||||
invoice = self.execute_query(get_query, invoice_id=invoice_id).fetchone()
|
||||
if invoice:
|
||||
hash = self.get_hash(invoice['id'], invoice['date_generation'],
|
||||
invoice['montant'])
|
||||
if hash == invoice_hash:
|
||||
return self.execute_query(query, invoice_id=invoice_id,
|
||||
status=status).fetchone()
|
|
@ -0,0 +1,64 @@
|
|||
{% extends "gdc/base.html" %}
|
||||
{% load i18n passerelle %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>Concerto - {{ object.title }}</h2>
|
||||
{% if perms.concerto.change_concerto %}
|
||||
<a rel="popup" class="button" href="{% url 'concerto-edit' slug=object.slug %}">{% trans 'edit' %}</a>
|
||||
{% endif %}
|
||||
{% if perms.concerto.delete_concerto %}
|
||||
<a rel="popup" class="button" href="{% url 'concerto-delete' slug=object.slug %}">{% trans 'delete' %}</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
<h3>{% trans 'Endpoints' %}</h3>
|
||||
<ul>
|
||||
|
||||
<li>{% trans "Check user's family link:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>familylink</i>/<family_id></i>/<i><secret></i></a>
|
||||
</li>
|
||||
<li>{% trans "Link to a family:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>linktofamily/<nameid></i>/<family_id></i></a>
|
||||
</li>
|
||||
<li>{% trans "Unlink from a family:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>unlinkfromfamily/<nameid></i></a>
|
||||
</li>
|
||||
<li>{% trans "NameId's families:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>familydata/<nameid>?filter=families</i></a>
|
||||
</li>
|
||||
<li>{% trans "Family's parents:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>familydata/<nameid>?filter=parents</i></a>
|
||||
</li>
|
||||
<li>{% trans "Family's kids:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>familydata/<nameid>?filter=kids</i></a>
|
||||
</li>
|
||||
<li>{% trans "Family's all invoices:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>familyallinvoices/<nameid></i></a>
|
||||
<li>{% trans "Family's unpaid invoices:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>familyallinvoices/<nameid>?status=unpaid</i></a>
|
||||
<li>{% trans "Invoice view:" %}
|
||||
<a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>invoice/<invoice_id>/<invoice_hash></i></a>
|
||||
</li>
|
||||
<li>{% trans "Invoice update:" %}
|
||||
POST on <a>{{ site_base_uri }}{% url 'concerto-view' slug=object.slug %}<i>invoice/<invoice_id>/<invoice_hash></i></a> with the 'status' in the payload
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% if perms.base.view_accessright %}
|
||||
<div>
|
||||
<h3>{% trans "Security" %}</h3>
|
||||
|
||||
<p>
|
||||
{% trans 'Accessing is limited to the following API users:' %}
|
||||
</p>
|
||||
|
||||
{% access_rights_table resource=object permission='can_use_connector' %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,30 @@
|
|||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.conf.urls import patterns, url
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from views import *
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^(?P<slug>[\w,-]+)/$', ConcertoDetailView.as_view(), name='concerto-view'),
|
||||
|
||||
url(r'^(?P<slug>[\w,-]+)/familylink/(?P<family_id>\w+)/(?P<secret>.+)$',
|
||||
FamilyLink.as_view(), name='concerto-familylink'),
|
||||
url(r'^(?P<slug>[\w,-]+)/familydata/(?P<nameid>.+)$',
|
||||
FamilyData.as_view(), name='concerto-familydata'),
|
||||
url(r'^(?P<slug>[\w,-]+)/linktofamily/(?P<nameid>.+)/(?P<family_id>\d+)$',
|
||||
LinkToFamily.as_view(), name='concerto-linktofamily'),
|
||||
url(r'^(?P<slug>[\w,-]+)/unlinkfromfamily/(?P<nameid>.+)$',
|
||||
UnlinkFromFamily.as_view(), name='concerto-unlinkfromfamily'),
|
||||
url(r'^(?P<slug>[\w,-]+)/famildata/(?P<nameid>.+)$',
|
||||
FamilyData.as_view(), name='concerto-familydata'),
|
||||
url(r'^(?P<slug>[\w,-]+)/familyallinvoices/(?P<nameid>.+)$',
|
||||
FamilyInvoices.as_view(), name='concerto-familyallinvoices'),
|
||||
url(r'^(?P<slug>[\w,-]+)/invoice/(?P<invoice_id>\w+)/(?P<invoice_hash>\w+)$',
|
||||
InvoiceView.as_view(), name='concerto-invoiceview'),
|
||||
)
|
||||
|
||||
|
||||
management_urlpatterns = patterns('',
|
||||
url(r'^add$', ConcertoCreateView.as_view(), name='concerto-add'),
|
||||
url(r'^(?P<slug>[\w,-]+)/edit$', ConcertoUpdateView.as_view(), name='concerto-edit'),
|
||||
url(r'^(?P<slug>[\w,-]+)/delete$', ConcertoDeleteView.as_view(), name='concerto-delete'),
|
||||
)
|
|
@ -0,0 +1,96 @@
|
|||
import json
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import Http404
|
||||
from django.shortcuts import redirect
|
||||
from django.views.generic.base import View, RedirectView
|
||||
from django.views.generic.detail import SingleObjectMixin, DetailView
|
||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||
|
||||
from passerelle.utils import to_json
|
||||
from passerelle import utils
|
||||
|
||||
from passerelle.base.views import ResourceView
|
||||
|
||||
from .models import Concerto
|
||||
from .forms import ConcertoForm
|
||||
|
||||
|
||||
class ConcertoDetailView(DetailView):
|
||||
model = Concerto
|
||||
|
||||
|
||||
class ConcertoCreateView(CreateView):
|
||||
model = Concerto
|
||||
form_class = ConcertoForm
|
||||
template_name = 'passerelle/manage/service_form.html'
|
||||
|
||||
|
||||
class ConcertoUpdateView(UpdateView):
|
||||
model = Concerto
|
||||
form_class = ConcertoForm
|
||||
template_name = 'passerelle/manage/service_form.html'
|
||||
|
||||
|
||||
class ConcertoDeleteView(DeleteView):
|
||||
model = Concerto
|
||||
template_name = 'passerelle/manage/service_confirm_delete.html'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('manage-home')
|
||||
|
||||
class FamilyLink(View, SingleObjectMixin):
|
||||
model = Concerto
|
||||
|
||||
@utils.protected_api('can_use_connector')
|
||||
@to_json('api')
|
||||
def get(self, request, slug, family_id, secret, *args, **kwargs):
|
||||
return self.get_object().family_link(family_id, secret)
|
||||
|
||||
class FamilyData(View, SingleObjectMixin):
|
||||
model = Concerto
|
||||
|
||||
@utils.protected_api('can_use_connector')
|
||||
@to_json('api')
|
||||
def get(self, request, slug, nameid):
|
||||
data_filter = request.GET.get('filter', None)
|
||||
return self.get_object().family_data(nameid, data_filter)
|
||||
|
||||
class LinkToFamily(View, SingleObjectMixin):
|
||||
model = Concerto
|
||||
|
||||
@utils.protected_api('can_use_connector')
|
||||
@to_json('api')
|
||||
def get(self, request, slug, nameid, family_id):
|
||||
return self.get_object().link_to_family(nameid, family_id)
|
||||
|
||||
class UnlinkFromFamily(View, SingleObjectMixin):
|
||||
model = Concerto
|
||||
|
||||
@utils.protected_api('can_use_connector')
|
||||
@to_json('api')
|
||||
def get(self, request, slug, nameid):
|
||||
return self.get_object().unlink_from_family(nameid)
|
||||
|
||||
class FamilyInvoices(View, SingleObjectMixin):
|
||||
model = Concerto
|
||||
|
||||
@utils.protected_api('can_use_connector')
|
||||
@to_json('api')
|
||||
def get(self, request, slug, nameid):
|
||||
status = request.GET.get('status', 'all')
|
||||
return self.get_object().family_invoices(nameid, status)
|
||||
|
||||
class InvoiceView(View, SingleObjectMixin):
|
||||
model = Concerto
|
||||
|
||||
@utils.protected_api('can_use_connector')
|
||||
@to_json('api')
|
||||
def get(self, request, slug, invoice_id, invoice_hash):
|
||||
return self.get_object().get_invoice(invoice_id, invoice_hash)
|
||||
|
||||
@utils.protected_api('can_use_connector')
|
||||
@to_json('api')
|
||||
def post(self, request, slug, invoice_id, invoice_hash):
|
||||
invoice_status = request.POST.get('status')
|
||||
return self.get_object().update_invoice(invoice_id, invoice_hash, invoice_status)
|
|
@ -88,6 +88,7 @@ INSTALLED_APPS = (
|
|||
'ovh',
|
||||
'mobyt',
|
||||
'pastell',
|
||||
'concerto',
|
||||
'gadjo',
|
||||
)
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
|
@ -23,3 +23,6 @@ li.clock a:hover { background-image: url(icons/icon-clock-hover.png); }
|
|||
|
||||
li.pastell a { background-image: url(icons/icon-pastell.png); }
|
||||
li.pastell a:hover { background-image: url(icons/icon-pastell-hover.png); }
|
||||
|
||||
li.concerto a { background-image: url(icons/icon-concerto.png); }
|
||||
li.concerto a:hover { background-image: url(icons/icon-concerto-hover.png); }
|
||||
|
|
|
@ -17,6 +17,7 @@ import mobyt.urls
|
|||
import ovh.urls
|
||||
import oxyd.urls
|
||||
import pastell.urls
|
||||
import concerto.urls
|
||||
|
||||
admin.autodiscover()
|
||||
|
||||
|
@ -64,6 +65,10 @@ urlpatterns = patterns('',
|
|||
url(r'^manage/pastell/',
|
||||
decorated_includes(login_required, include(pastell.urls.management_urlpatterns))),
|
||||
|
||||
url(r'^concerto/', include(concerto.urls.urlpatterns)),
|
||||
url(r'^manage/concerto/',
|
||||
decorated_includes(login_required, include(concerto.urls.management_urlpatterns))),
|
||||
|
||||
)
|
||||
|
||||
# activate URL for installed apps only
|
||||
|
|
Loading…
Reference in New Issue