Merge branch 'wf-services'
This commit is contained in:
commit
fdcf5b2aa4
|
@ -13,9 +13,15 @@ API_PATHS = {
|
||||||
'my-account': 'accounts/',
|
'my-account': 'accounts/',
|
||||||
|
|
||||||
# services
|
# services
|
||||||
|
'database-list': 'databases/',
|
||||||
'domain-list': 'domains/',
|
'domain-list': 'domains/',
|
||||||
|
'address-list': 'addresses/',
|
||||||
|
'mailbox-list': 'mailboxes/',
|
||||||
'mailinglist-list': 'lists/',
|
'mailinglist-list': 'lists/',
|
||||||
# ... TODO (@slamora) complete list of backend URLs
|
# ... TODO (@slamora) complete list of backend URLs
|
||||||
|
|
||||||
|
# other
|
||||||
|
'payment-source-list': 'payment-sources/',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,27 @@ class CustomContextMixin(ContextMixin):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class ExtendedPaginationMixin:
|
||||||
|
paginate_by = 20
|
||||||
|
paginate_by_kwarg = 'per_page'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context.update({
|
||||||
|
'per_page_values': [5, 10, 20, 50],
|
||||||
|
'per_page_param': self.paginate_by_kwarg,
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_paginate_by(self, queryset):
|
||||||
|
per_page = self.request.GET.get(self.paginate_by_kwarg) or self.paginate_by
|
||||||
|
try:
|
||||||
|
paginate_by = int(per_page)
|
||||||
|
except ValueError:
|
||||||
|
paginate_by = self.paginate_by
|
||||||
|
return paginate_by
|
||||||
|
|
||||||
|
|
||||||
class UserTokenRequiredMixin(UserPassesTestMixin):
|
class UserTokenRequiredMixin(UserPassesTestMixin):
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
"""Check that the user has an authorized token."""
|
"""Check that the user has an authorized token."""
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
from django.utils.html import format_html
|
||||||
|
|
||||||
|
|
||||||
|
class OrchestraModel:
|
||||||
|
""" Base class from which all orchestra models will inherit. """
|
||||||
|
api_name = None
|
||||||
|
verbose_name = None
|
||||||
|
fields = ()
|
||||||
|
param_defaults = {}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
if self.verbose_name is None:
|
||||||
|
self.verbose_name = self.api_name
|
||||||
|
|
||||||
|
for (param, default) in self.param_defaults.items():
|
||||||
|
setattr(self, param, kwargs.get(param, default))
|
||||||
|
|
||||||
|
# def get(self, key):
|
||||||
|
# # retrieve attr of the object and if undefined get raw data
|
||||||
|
# return getattr(self, key, self.data.get(key))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def new_from_json(cls, data, **kwargs):
|
||||||
|
""" Create a new instance based on a JSON dict. Any kwargs should be
|
||||||
|
supplied by the inherited, calling class.
|
||||||
|
Args:
|
||||||
|
data: A JSON dict, as converted from the JSON in the orchestra API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
json_data = data.copy()
|
||||||
|
if kwargs:
|
||||||
|
for key, val in kwargs.items():
|
||||||
|
json_data[key] = val
|
||||||
|
|
||||||
|
c = cls(**json_data)
|
||||||
|
c._json = data
|
||||||
|
# TODO(@slamora) remove/replace by private variable to ovoid name collisions
|
||||||
|
c.data = data
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
class BillingContact(OrchestraModel):
|
||||||
|
param_defaults = {
|
||||||
|
'name': None,
|
||||||
|
'address': None,
|
||||||
|
'city': None,
|
||||||
|
'zipcode': None,
|
||||||
|
'country': None,
|
||||||
|
'vat': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentSource(OrchestraModel):
|
||||||
|
api_name = 'payment-source'
|
||||||
|
param_defaults = {
|
||||||
|
"method": None,
|
||||||
|
"data": [],
|
||||||
|
"is_active": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UserAccount(OrchestraModel):
|
||||||
|
api_name = 'accounts'
|
||||||
|
param_defaults = {
|
||||||
|
'username': None,
|
||||||
|
'type': None,
|
||||||
|
'language': None,
|
||||||
|
'short_name': None,
|
||||||
|
'full_name': None,
|
||||||
|
'billing': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def new_from_json(cls, data, **kwargs):
|
||||||
|
billing = None
|
||||||
|
|
||||||
|
if 'billcontact' in data:
|
||||||
|
billing = BillingContact.new_from_json(data['billcontact'])
|
||||||
|
return super().new_from_json(data=data, billing=billing)
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseUser(OrchestraModel):
|
||||||
|
api_name = 'databaseusers'
|
||||||
|
fields = ('username',)
|
||||||
|
param_defaults = {
|
||||||
|
'username': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseService(OrchestraModel):
|
||||||
|
api_name = 'database'
|
||||||
|
fields = ('name', 'type', 'users')
|
||||||
|
param_defaults = {
|
||||||
|
"id": None,
|
||||||
|
"name": None,
|
||||||
|
"type": None,
|
||||||
|
"users": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def new_from_json(cls, data, **kwargs):
|
||||||
|
users = None
|
||||||
|
if 'users' in data:
|
||||||
|
users = [DatabaseUser.new_from_json(user_data) for user_data in data['users']]
|
||||||
|
return super().new_from_json(data=data, users=users)
|
||||||
|
|
||||||
|
|
||||||
|
class MailService(OrchestraModel):
|
||||||
|
api_name = 'address'
|
||||||
|
verbose_name = 'Mail'
|
||||||
|
fields = ('mail_address', 'aliases', 'type', 'type_detail')
|
||||||
|
|
||||||
|
FORWARD = 'forward'
|
||||||
|
MAILBOX = 'mailbox'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def aliases(self):
|
||||||
|
return [
|
||||||
|
name + '@' + self.data['domain']['name'] for name in self.data['names'][1:]
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mail_address(self):
|
||||||
|
return self.data['names'][0] + '@' + self.data['domain']['name']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
if self.data['forward']:
|
||||||
|
return self.FORWARD
|
||||||
|
return self.MAILBOX
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type_detail(self):
|
||||||
|
if self.type == self.FORWARD:
|
||||||
|
return self.data['forward']
|
||||||
|
# TODO(@slamora) retrieve mailbox usage
|
||||||
|
return {'usage': 0, 'total': 213}
|
||||||
|
|
||||||
|
|
||||||
|
class MailinglistService(OrchestraModel):
|
||||||
|
api_name = 'mailinglist'
|
||||||
|
verbose_name = 'Mailing list'
|
||||||
|
fields = ('name', 'status', 'address_name', 'admin_email', 'configure')
|
||||||
|
param_defaults = {
|
||||||
|
'name': None,
|
||||||
|
'admin_email': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self):
|
||||||
|
# TODO(@slamora): where retrieve if the list is active?
|
||||||
|
return 'active'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def address_name(self):
|
||||||
|
return "{}@{}".format(self.data['address_name'], self.data['address_domain']['name'])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def configure(self):
|
||||||
|
# TODO(@slamora): build mailtran absolute URL
|
||||||
|
return format_html('<a href="#TODO">Mailtrain</a>')
|
|
@ -0,0 +1,29 @@
|
||||||
|
{# <!-- paginator component --> #}
|
||||||
|
<div class="row object-list-paginator">
|
||||||
|
<div class="col-md-4">{{ page_obj.paginator.count }} items in total</div>
|
||||||
|
<div class="col-md-4 text-center">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a href="?page=1&per_page={{ page_obj.paginator.per_page }}">«</a>
|
||||||
|
<a href="?page={{ page_obj.previous_page_number }}&per_page={{ page_obj.paginator.per_page }}">‹</a>
|
||||||
|
{% endif %}
|
||||||
|
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a href="?page={{ page_obj.next_page_number }}&per_page={{ page_obj.paginator.per_page }}">›</a>
|
||||||
|
<a href="?page={{ page_obj.paginator.num_pages }}&per_page={{ page_obj.paginator.per_page }}">»</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 text-right">
|
||||||
|
<form method="get">
|
||||||
|
Showing
|
||||||
|
<select name="{{ per_page_param }}">
|
||||||
|
{% for value in per_page_values %}
|
||||||
|
{% with page_obj.paginator.per_page as per_page %}
|
||||||
|
<option value="{{ value }}" {% if value == per_page %}selected{% endif %}>{{ value }}</option>
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
per page
|
||||||
|
<input type="submit" value="apply" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -3,7 +3,50 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<h1>Section title</h1>
|
<h1>{{ service.verbose_name }}</h1>
|
||||||
<p>Little description of what to be expected...</p>
|
<p>{{ service.description }}</p>
|
||||||
|
|
||||||
|
{% for database in object_list %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<strong>{{ database.name }}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-md">
|
||||||
|
Type: <strong>{{ database.type }}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-md text-right">
|
||||||
|
associated to: <strong>{{ database.domain|default:"-" }}</strong>
|
||||||
|
<div class="card-collapse-button d-inline-block nav-item dropdown">
|
||||||
|
<button class="btn dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- /card-header-->
|
||||||
|
<div class="card-body row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h4>Database users</h4>
|
||||||
|
<ul>
|
||||||
|
{% for user in resource.users %}
|
||||||
|
<li>{{ user.username }}</li>
|
||||||
|
{% empty %}
|
||||||
|
<li>No users for this database.</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2 border-left border-right">
|
||||||
|
<h4>Database usage</h4>
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar w-75" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100">75%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 text-right">
|
||||||
|
<a class="btn btn-secondary" href="#open-phpmyadmin">Open database manager</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% include "musician/components/paginator.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -3,7 +3,27 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<h1>Section title</h1>
|
<h1>{{ service.verbose_name }}</h1>
|
||||||
<p>Little description of what to be expected...</p>
|
<p>{{ service.description }}</p>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Mail address</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
<th scope="col">Type</th>
|
||||||
|
<th scope="col">Type details</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for obj in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ obj.mail_address }}</td>
|
||||||
|
<td>{{ obj.aliases|join:" , " }}</td>
|
||||||
|
<td>{{ obj.type }}</td>
|
||||||
|
<td>{{ obj.type_detail }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
{% include "musician/components/table_paginator.html" %}
|
||||||
|
</table>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
{% extends "musician/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Profile</h1>
|
||||||
|
<p>Little description of what to be expected...</p>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<h5 class="card-header text-right">User information</h5>
|
||||||
|
<div class="card-body row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="m-auto border border-secondary rounded-circle rounded-lg" style="width:125px; height:125px;">
|
||||||
|
{# <!-- <img class="" src="#" alt="User profile image" /> -->#}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<p class="card-text">{{ profile.username }}</p>
|
||||||
|
<p class="card-text">{{ profile.type }}</p>
|
||||||
|
<p class="card-text">Preferred language: {{ profile.language }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% with profile.billing as contact %}
|
||||||
|
<div class="card mt-4">
|
||||||
|
<h5 class="card-header text-right">Billing information</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="form-group">{{ contact.name }}</div>
|
||||||
|
<div class="form-group">{{ contact.address }}</div>
|
||||||
|
<div class="form-group">
|
||||||
|
{{ contact.zipcode }}
|
||||||
|
{{ contact.city }}
|
||||||
|
{{ contact.country }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
{{ contact.vat }}
|
||||||
|
</div>
|
||||||
|
<!-- payment method -->
|
||||||
|
<div class="form-group">
|
||||||
|
payment method: {{ payment.method }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
{# TODO(@slamora) format payment method details #}
|
||||||
|
{{ payment.data.data }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,28 @@
|
||||||
|
{% extends "musician/base.html" %}
|
||||||
|
{% load i18n musician %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{{ service.verbose_name }}</h1>
|
||||||
|
<p>{{ service.description }}</p>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
{% for field_name in service.fields %}
|
||||||
|
<th scope="col">{{ field_name }}</th>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for resource in object_list %}
|
||||||
|
<tr>
|
||||||
|
{% for field_name in service.fields %}
|
||||||
|
<td>{{ resource|get_item:field_name }}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
{% include "musician/components/table_paginator.html" %}
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,6 @@
|
||||||
|
from django.template.defaulttags import register
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def get_item(dictionary, key):
|
||||||
|
return dictionary.get(key)
|
|
@ -15,6 +15,7 @@ urlpatterns = [
|
||||||
path('auth/login/', views.LoginView.as_view(), name='login'),
|
path('auth/login/', views.LoginView.as_view(), name='login'),
|
||||||
path('auth/logout/', views.LogoutView.as_view(), name='logout'),
|
path('auth/logout/', views.LogoutView.as_view(), name='logout'),
|
||||||
path('dashboard/', views.DashboardView.as_view(), name='dashboard'),
|
path('dashboard/', views.DashboardView.as_view(), name='dashboard'),
|
||||||
|
path('profile/', views.ProfileView.as_view(), name='profile'),
|
||||||
path('mails/', views.MailView.as_view(), name='mails'),
|
path('mails/', views.MailView.as_view(), name='mails'),
|
||||||
path('mailing-lists/', views.MailingListsView.as_view(), name='mailing-lists'),
|
path('mailing-lists/', views.MailingListsView.as_view(), name='mailing-lists'),
|
||||||
path('databases/', views.DatabasesView.as_view(), name='databases'),
|
path('databases/', views.DatabasesView.as_view(), name='databases'),
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
|
|
||||||
|
from django.views.generic.detail import DetailView
|
||||||
|
from itertools import groupby
|
||||||
|
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
@ -11,7 +15,9 @@ from . import api, get_version
|
||||||
from .auth import login as auth_login
|
from .auth import login as auth_login
|
||||||
from .auth import logout as auth_logout
|
from .auth import logout as auth_logout
|
||||||
from .forms import LoginForm
|
from .forms import LoginForm
|
||||||
from .mixins import CustomContextMixin, UserTokenRequiredMixin
|
from .mixins import (CustomContextMixin,
|
||||||
|
ExtendedPaginationMixin, UserTokenRequiredMixin)
|
||||||
|
from .models import DatabaseService, MailinglistService, MailService, UserAccount, PaymentSource
|
||||||
|
|
||||||
|
|
||||||
class DashboardView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
|
class DashboardView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
|
||||||
|
@ -30,38 +36,84 @@ class DashboardView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class MailView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
|
class ProfileView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
|
||||||
template_name = "musician/mail.html"
|
template_name = "musician/profile.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
json_data = self.orchestra.retreve_profile()
|
||||||
|
try:
|
||||||
|
pay_source = self.orchestra.retrieve_service_list(
|
||||||
|
PaymentSource.api_name)[0]
|
||||||
|
except IndexError:
|
||||||
|
pay_source = {}
|
||||||
|
context.update({
|
||||||
|
'profile': UserAccount.new_from_json(json_data[0]),
|
||||||
|
'payment': PaymentSource.new_from_json(pay_source)
|
||||||
|
})
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class MailingListsView(CustomContextMixin, UserTokenRequiredMixin, ListView):
|
class ServiceListView(CustomContextMixin, ExtendedPaginationMixin, UserTokenRequiredMixin, ListView):
|
||||||
template_name = "musician/mailinglists.html"
|
"""Base list view to all services"""
|
||||||
paginate_by = 20
|
service_class = None
|
||||||
paginate_by_kwarg = 'per_page'
|
template_name = "musician/service_list.html" # TODO move to ServiceListView
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.orchestra.retrieve_service_list('mailinglist')
|
if self.service_class is None or self.service_class.api_name is None:
|
||||||
|
raise ImproperlyConfigured(
|
||||||
|
"ServiceListView requires a definiton of 'service'")
|
||||||
|
|
||||||
|
json_qs = self.orchestra.retrieve_service_list(
|
||||||
|
self.service_class.api_name)
|
||||||
|
return [self.service_class.new_from_json(data) for data in json_qs]
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context.update({
|
context.update({
|
||||||
'page_param': self.page_kwarg,
|
'service': self.service_class,
|
||||||
'per_page_values': [5, 10, 20, 50],
|
|
||||||
'per_page_param': self.paginate_by_kwarg,
|
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_paginate_by(self, queryset):
|
|
||||||
per_page = self.request.GET.get(self.paginate_by_kwarg) or self.paginate_by
|
class MailView(ServiceListView):
|
||||||
try:
|
service_class = MailService
|
||||||
paginate_by = int(per_page)
|
template_name = "musician/mail.html"
|
||||||
except ValueError:
|
|
||||||
paginate_by = self.paginate_by
|
def get_queryset(self):
|
||||||
return paginate_by
|
def retrieve_mailbox(value):
|
||||||
|
mailboxes = value.get('mailboxes')
|
||||||
|
|
||||||
|
if len(mailboxes) == 0:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
return mailboxes[0]['id']
|
||||||
|
|
||||||
|
# group addresses with the same mailbox
|
||||||
|
raw_data = self.orchestra.retrieve_service_list(
|
||||||
|
self.service_class.api_name)
|
||||||
|
addresses = []
|
||||||
|
for key, group in groupby(raw_data, retrieve_mailbox):
|
||||||
|
aliases = []
|
||||||
|
data = {}
|
||||||
|
for thing in group:
|
||||||
|
aliases.append(thing.pop('name'))
|
||||||
|
data = thing
|
||||||
|
|
||||||
|
data['names'] = aliases
|
||||||
|
addresses.append(self.service_class.new_from_json(data))
|
||||||
|
|
||||||
|
return addresses
|
||||||
|
|
||||||
|
|
||||||
class DatabasesView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
|
class MailingListsView(ServiceListView):
|
||||||
|
service_class = MailinglistService
|
||||||
|
|
||||||
|
|
||||||
|
class DatabasesView(ServiceListView):
|
||||||
template_name = "musician/databases.html"
|
template_name = "musician/databases.html"
|
||||||
|
service_class = DatabaseService
|
||||||
|
|
||||||
|
|
||||||
class SaasView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
|
class SaasView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
|
||||||
|
|
Loading…
Reference in New Issue