family: clean app, remove unused models (#56015)
gitea-wip/combo/pipeline/head There was a failure building this commit Details
gitea/combo/pipeline/head Build queued... Details

This commit is contained in:
Lauréline Guérin 2021-09-27 14:21:34 +02:00
parent b5e7234acd
commit 71a362bb14
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
16 changed files with 20 additions and 555 deletions

View File

@ -1,8 +0,0 @@
Combo family cell
=================
To be visible, this cell needs a 'passerelle' entry in settings.KNOWN_SERVICES
(see ../wcs/README) and a FAMILY_SERVICE attribute in settings:
FAMILY_SERVICE = {'root': '/connector/instance/'}

View File

@ -1,31 +0,0 @@
# combo - content management system
# Copyright (C) 2015 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import django.apps
from django.utils.translation import ugettext_lazy as _
class AppConfig(django.apps.AppConfig):
name = 'combo.apps.family'
verbose_name = _('Family')
def get_before_urls(self):
from . import urls
return urls.urlpatterns
default_app_config = 'combo.apps.family.AppConfig'

View File

@ -1,27 +0,0 @@
# combo - content management system
# Copyright (C) 2015 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django import forms
from django.utils.translation import ugettext_lazy as _
class FamilyLinkForm(forms.Form):
family_id = forms.CharField(
label=_('Family identifier'), widget=forms.TextInput(attrs={'required': 'required'})
)
family_code = forms.CharField(
label=_('Secret code'), widget=forms.PasswordInput(attrs={'required': 'required'})
)

View File

@ -0,0 +1,14 @@
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('family', '0007_weekly_agenda_user_template'),
]
operations = [
migrations.DeleteModel(
name='FamilyInfosCell',
),
]

View File

@ -19,39 +19,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from combo.data.library import register_cell_class
from combo.data.models import CellBase, JsonCellBase
from .utils import get_family, is_family_enabled
@register_cell_class
class FamilyInfosCell(CellBase):
default_template_name = 'family/infos.html'
user_dependant = True
class Meta:
verbose_name = _('Family Information Cell')
class Media:
js = (
'xstatic/jquery-ui.min.js',
'js/gadjo.js',
)
@classmethod
def is_enabled(cls):
return is_family_enabled()
def get_cell_extra_context(self, context):
if context.get('placeholder_search_mode'):
return {}
user = self.get_concerned_user(context)
if not user or user.is_anonymous:
return {}
response = get_family(user=user, raise_if_not_cached=not (context.get('synchronous')))
if response.status_code == 200:
return {'family': response.json()}
return {'error': _('An error occured while retrieving family details.')}
from combo.data.models import JsonCellBase
@register_cell_class

View File

@ -1,66 +0,0 @@
{% load i18n %}
{% block cell-content %}
<h2>{% trans "Informations related to your family" %}</h2>
{% trans "Top content for unlinked users" as top_content %}
{% placeholder "family_unlinked_user" name=top_content render=False %}
<div>
{% if not user.is_authenticated %}
{% placeholder "family_unlinked_user" %}
{% elif error %}
<p>{{error}}</p>
{% elif not family.data %}
{% url 'family-link' as link_url %}
{% placeholder "family_unlinked_user" %}
<div class="family-link">
<a href="{{ link_url }}" rel="popup">{% trans "Link to your family" %}</a>
</div>
{% else %}
<div class="family_unlink">
<a href="{% url 'family-unlink' %}" rel="popup">{% trans "Unlink" %}</a>
</div>
{% with data=family.data %}
{% if data.address or data.quotient %}
<div class="family-data">
{% if data.address %}
<div class="address">
<h4>{% trans "Address" %}</h4>
<p>{{ data.address }}</p>
</div>
{% endif %}
{% if data.quotient %}
<p class="family-quotient">
<span class="label">{% trans "Family quotient:" %}</span>
<span class="value">{{ data.quotient }}</span>
</p>
{% endif %}
</div>
{% endif %}
<div class="family_members">
{% if data.adults %}
<div class="family_adults">
<h3>{% trans "Adults" %}</h3>
{% for adult in data.adults %}
<div>
{% include 'family/person.html' with person=adult %}
</div>
{% endfor %}
</div>
{% endif %}
{% if data.children %}
<div class="family_children">
<h3>{% trans "Children" %}</h3>
{% for child in data.children %}
<div>
{% include 'family/person.html' with person=child %}
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endwith %}
{% endif %}
</div>
{% endblock %}

View File

@ -1,27 +0,0 @@
{% load i18n %}
<div id="content">
<div id="appbar">
<h2>{% trans "Link to a family" %}</h2>
</div>
<form method="post" class="quixote" action='{% url "family-link" %}'>
{% csrf_token %}
{% if family_link_intro_text %}
{{family_link_intro_text|linebreaks}}
{% else %}
<p>
{% blocktrans %}
Enter your family credentials below.
{% endblocktrans %}
</p>
{% endif %}
{% for field in form %}
<div class="widget grid-1-2">
<div class="title"><label>{{field.label_tag}}</label></div>
<div class="content">{{field}}</div>
</div>
{% endfor %}
<div class="buttons">
<button class="submit-button">{% trans "Submit" %}</button>
</div>
</form>
</div>

View File

@ -1,36 +0,0 @@
{% load i18n %}
<p class="name"><span>{{ person.first_name }} {{ person.last_name }}</span></p>
{% if person.birthdate %}
<p class="birthdate">
<span class="label">{% trans "Born on" %}</span>
<span class="value">{{ person.birthdate }}</span>
</p>
{% endif %}
<div class="address">
<h4>{% trans "Address" %}</h4>
<p>{{ person.address }}</p>
</div>
{% if person.phone or person.cellphone or person.email %}
<div class="contact">
{% if person.phone %}
<p class="phone">
<span class="label">{% trans "Phone:" %}</span>
<span class="value">{{ person.phone }}</span>
</p>
{% endif %}
{% if person.cellphone %}
<p class="cellphone">
<span class="label">{% trans "Cellphone:" %}</span>
<span class="value">{{ person.cellphone }}</span>
</p>
{% endif %}
{% if person.email %}
<p class="email">
<span class="label">{% trans "Email:" %}</span>
<span class="value"{{ person.email }}</span>
</p>
{% endif %}
</div>
{% endif %}

View File

@ -1,11 +0,0 @@
{% load i18n %}
<div id="content">
<form method="post">
{% csrf_token %}
{% trans "Unlink your personal account from this family account?" %}
<div class="buttons">
<button class="delete-button">{% trans 'Unlink' %}</button>
</div>
</form>
</div>

View File

@ -1,24 +0,0 @@
# combo - content management system
# Copyright (C) 2015 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.conf.urls import url
from .views import FamilyLinkView, FamilyUnlinkView
urlpatterns = [
url(r'^family/link/?$', FamilyLinkView.as_view(), name='family-link'),
url(r'^family/unlink/?$', FamilyUnlinkView.as_view(), name='family-unlink'),
]

View File

@ -1,61 +0,0 @@
# combo - content management system
# Copyright (C) 2015-2016 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.conf import settings
from combo.utils import requests
def get_passerelle_service():
try:
return [x for x in settings.KNOWN_SERVICES['passerelle'].values() if not x.get('secondary')][0]
except (AttributeError, IndexError, KeyError):
return None
def is_family_enabled():
return get_passerelle_service() and hasattr(settings, 'FAMILY_SERVICE')
def remote_service(endpoint, **kwargs):
path = settings.FAMILY_SERVICE.get('root') + endpoint
return requests.get(
path, remote_service=get_passerelle_service(), headers={'accept': 'application/json'}, **kwargs
)
def get_family(**kwargs):
endpoint = 'family/'
return remote_service(endpoint, **kwargs)
def link_family(user, family_id, family_code):
endpoint = 'family/link/'
kwargs = {
'user': user,
'invalidate_cache': True,
'params': {
'login': family_id,
'password': family_code,
},
}
return remote_service(endpoint, **kwargs)
def unlink_family(user):
endpoint = 'family/unlink/'
kwargs = {'user': user, 'invalidate_cache': True}
return remote_service(endpoint, **kwargs)

View File

@ -1,72 +0,0 @@
# combo - content management system
# Copyright (C) 2015 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView, TemplateView
from .forms import FamilyLinkForm
from .utils import link_family, unlink_family
ERROR_MESSAGES = {
100: _('Wrong credentials: make sure you typed them correctly.'),
101: _('This family account is blocked.'),
}
class FamilyLinkView(FormView):
form_class = FamilyLinkForm
template_name = 'family/link_form.html'
def get_success_url(self):
if self.request.META.get('HTTP_REFERER'):
return self.request.META['HTTP_REFERER']
# return to current location if no referer
return '.'
def form_valid(self, form):
response = link_family(
self.request.user, form.cleaned_data['family_id'], form.cleaned_data['family_code']
)
if not response.ok or response.json().get('err'):
error_code = response.json().get('err')
error_message = ERROR_MESSAGES.get(
error_code, _('Failed to link to family. Please check your credentials and retry later.')
)
messages.error(self.request, error_message)
else:
messages.info(self.request, _('Your account was successfully linked.'))
return super().form_valid(form)
class FamilyUnlinkView(TemplateView):
template_name = 'family/unlink_confirm.html'
def post(self, request, *args, **kwargs):
response = unlink_family(request.user)
if not response.ok or response.json().get('err'):
messages.error(request, _('An error occured when unlinking.'))
else:
messages.info(request, _('Your account was successfully unlinked.'))
if self.request.META.get('HTTP_REFERER'):
return HttpResponseRedirect(self.request.META['HTTP_REFERER'])
# fallback to homepage if no referer
return HttpResponseRedirect('/')

View File

@ -79,8 +79,6 @@ if 'DISABLE_MIGRATIONS' in os.environ:
MIGRATION_MODULES = DisableMigrations()
FAMILY_SERVICE = {'root': '/'}
BOOKING_CALENDAR_CELL_ENABLED = True
LEGACY_CHART_CELL_ENABLED = True

View File

@ -27,7 +27,6 @@ from pyquery import PyQuery
from webtest import Upload
from combo.apps.assets.models import Asset
from combo.apps.family.models import FamilyInfosCell
from combo.apps.maps.models import MapLayer
from combo.apps.search.models import SearchCell
from combo.data.forms import LinkCellForm
@ -895,7 +894,7 @@ def test_site_export_import_json(app, admin_user):
resp.form['site_file'] = Upload('site-export.json', site_export, 'application/json')
with CaptureQueriesContext(connection) as ctx:
resp = resp.form.submit()
assert len(ctx.captured_queries) in [307, 308]
assert len(ctx.captured_queries) in [302, 303]
assert Page.objects.count() == 4
assert PageSnapshot.objects.all().count() == 4
@ -906,7 +905,7 @@ def test_site_export_import_json(app, admin_user):
resp.form['site_file'] = Upload('site-export.json', site_export, 'application/json')
with CaptureQueriesContext(connection) as ctx:
resp = resp.form.submit()
assert len(ctx.captured_queries) == 276
assert len(ctx.captured_queries) == 272
assert set(Page.objects.get(slug='one').related_cells['cell_types']) == {'data_textcell', 'data_linkcell'}
assert Page.objects.count() == 4
assert LinkCell.objects.count() == 2
@ -2156,22 +2155,6 @@ def test_page_cell_placeholder(app, admin_user):
assert re.findall('<h2>(.*)</h2>', resp.text) == ['Page - One', 'Content', 'JSON Prototype / Foobar']
def test_page_familycell_placeholder(app, admin_user):
page = Page(title='My family', slug='my-family', template_name='standard')
page.save()
cell = FamilyInfosCell(page=page, placeholder='content', order=0)
cell.save()
app = login(app)
resp = app.get('/manage/pages/%s/' % page.id)
assert re.findall('data-placeholder-key="(.*)">', resp.text) == ['content', "family_unlinked_user"]
assert re.findall('<h2>(.*)</h2>', resp.text) == [
'Page - My family',
'Content',
'Family Information Cell / Top content for unlinked users',
]
def test_page_discover_placeholder_with_error_cells(app, admin_user):
page = Page(title='One', slug='one', template_name='standard')
page.save()
@ -2237,7 +2220,7 @@ def test_page_versionning(app, admin_user):
with CaptureQueriesContext(connection) as ctx:
resp2 = resp.click('view', index=1)
assert len(ctx.captured_queries) == 71
assert len(ctx.captured_queries) == 70
assert Page.snapshots.latest('pk').related_cells == {'cell_types': ['data_textcell']}
assert resp2.text.index('Hello world') < resp2.text.index('Foobar3')
@ -2298,7 +2281,7 @@ def test_page_versionning(app, admin_user):
resp = resp.click('restore', index=6)
with CaptureQueriesContext(connection) as ctx:
resp = resp.form.submit().follow()
assert len(ctx.captured_queries) == 146
assert len(ctx.captured_queries) == 144
resp2 = resp.click('See online')
assert resp2.text.index('Foobar1') < resp2.text.index('Foobar2') < resp2.text.index('Foobar3')

View File

@ -23,7 +23,6 @@ except ImportError:
import requests
from combo.apps.assets.models import Asset
from combo.apps.family.models import FamilyInfosCell
from combo.data.models import (
ConfigJsonCell,
FeedCell,
@ -840,140 +839,6 @@ def test_post_cell(app):
assert resp2.content == b'a,b\n1,2'
def test_familyinfos_cell_with_placeholders(app, admin_user):
Page.objects.all().delete()
page = Page(title='Family', slug='index', template_name='standard')
page.save()
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
family_cell.save()
TextCell(
page=page,
placeholder='family_unlinked_user',
text='<p>Hello anonymous user</p>',
order=0,
restricted_to_unlogged=True,
public=True,
).save()
TextCell(
page=page,
placeholder='family_unlinked_user',
text='<p>You are not linked</p>',
order=1,
public=False,
restricted_to_unlogged=False,
).save()
with override_settings(FAMILY_SERVICE={'root': '/family/'}):
with mock.patch('combo.utils.requests.send') as requests_send:
resp = app.get('/')
assert "<p>Hello anonymous user</p>" in resp.text
assert "<p>You are not linked</p>" not in resp.text
app = login(app)
data = {'err': 0, 'data': None}
requests_send.return_value = mock.Mock(
json=lambda: data, content=json.dumps(data), status_code=200
)
# make sure no data are loaded
resp = app.get('/')
assert resp.html.body.find('div', {'class': 'familyinfoscell'}).text.strip() == 'Loading...'
# put data in cache
resp = app.get(
reverse(
'combo-public-ajax-page-cell',
kwargs={'page_pk': page.pk, 'cell_reference': family_cell.get_reference()},
)
)
resp = app.get('/')
assert "<p>Hello anonymous user</p>" not in resp.text
assert "<p>You are not linked</p>" in resp.text
@mock.patch('combo.utils.requests.get')
def test_familycell_link(requests_get, app, settings, admin_user):
settings.FAMILY_SERVICE = {'root': '/family/'}
Page.objects.all().delete()
page = Page(title='Family', slug='index', template_name='standard')
page.save()
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
family_cell.save()
TextCell(
page=page,
placeholder='family_unlinked_user',
text='<p>Hello anonymous user</p>',
order=0,
restricted_to_unlogged=True,
public=True,
).save()
TextCell(
page=page,
placeholder='family_unlinked_user',
text='<p>You are not linked</p>',
order=1,
public=False,
restricted_to_unlogged=False,
).save()
app = login(app)
# when linking fails
requests_get.return_value = mock.Mock(ok=False, json=lambda: {'err': 102})
resp = app.get('/family/link/')
resp.form['family_id'] = '123'
resp.form['family_code'] = 'l33t'
resp = resp.form.submit().follow()
messages = resp.context['messages']
assert len(messages._loaded_messages) == 1
assert (
messages._loaded_messages[0].message
== 'Failed to link to family. Please check your credentials and retry later.'
)
requests_get.return_value = mock.Mock(ok=True, json=lambda: {})
resp.form['family_id'] = '123'
resp.form['family_code'] = 'l33t'
resp = resp.form.submit().follow()
messages = resp.context['messages']
assert len(messages._loaded_messages) == 2
assert messages._loaded_messages[1].message == 'Your account was successfully linked.'
@mock.patch('combo.utils.requests.get')
def test_familycell_unlink(requests_get, app, settings, admin_user):
settings.FAMILY_SERVICE = {'root': '/family/'}
Page.objects.all().delete()
page = Page(title='Family', slug='index', template_name='standard')
page.save()
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
family_cell.save()
TextCell(
page=page,
placeholder='family_unlinked_user',
text='<p>Hello anonymous user</p>',
order=0,
restricted_to_unlogged=True,
public=True,
).save()
TextCell(
page=page,
placeholder='family_unlinked_user',
text='<p>You are not linked</p>',
order=1,
public=False,
restricted_to_unlogged=False,
).save()
app = login(app)
requests_get.return_value = mock.Mock(ok=False, json=lambda: {'err': 102})
resp = app.get('/family/unlink/')
resp = resp.form.submit().follow()
messages = resp.context['messages']
assert len(messages._loaded_messages) == 1
assert messages._loaded_messages[0].message == 'An error occured when unlinking.'
requests_get.return_value = mock.Mock(ok=True, json=lambda: {})
resp = app.get('/family/unlink/')
resp = resp.form.submit().follow()
messages = resp.context['messages']
assert len(messages._loaded_messages) == 2
assert messages._loaded_messages[1].message == 'Your account was successfully unlinked.'
def test_synchronous_placeholder(app):
page = Page(title='foo', slug='foo', template_name='standard', order=0)
page.save()

View File

@ -1370,7 +1370,7 @@ def test_index_site_num_queries(settings, app):
assert IndexedCell.objects.count() == 50
with CaptureQueriesContext(connection) as ctx:
index_site()
assert len(ctx.captured_queries) == 223
assert len(ctx.captured_queries) == 222
SearchCell.objects.create(
page=page, placeholder='content', order=0, _search_services={'data': ['search1']}