Compare commits
42 Commits
wip/55535-
...
main
Author | SHA1 | Date |
---|---|---|
Valentin Deniaud | c3eb561c16 | |
Valentin Deniaud | ebc92cfc7f | |
Thomas NOËL | 6e2eac43a6 | |
Thomas NOËL | 5689cf1f0a | |
Frédéric Péters | a71993b73f | |
Frédéric Péters | 7d6b3549b3 | |
Frédéric Péters | 9d333b9957 | |
Valentin Deniaud | c04a5c50bd | |
Valentin Deniaud | 103dff03cb | |
Valentin Deniaud | 5f5d814feb | |
Thomas NOËL | 2c88fcfa68 | |
Frédéric Péters | a9eab5c891 | |
Agate | 7c9e166981 | |
Frédéric Péters | eb44518502 | |
Frédéric Péters | 2bc91fff29 | |
Frédéric Péters | 8242b1b6b9 | |
Agate | 295e994b83 | |
Agate | ee871ebc33 | |
Agate | ed3fc882cd | |
Agate | d8786aae95 | |
Agate | e1f969f813 | |
Agate | 3d9481f67d | |
Frédéric Péters | f0c32435c6 | |
Frédéric Péters | 9e165aebfc | |
Serghei Mihai | da41d0b6bd | |
Serghei Mihai | e2934f92c6 | |
Frédéric Péters | 549fc3ec00 | |
Thomas NOËL | eebe703fca | |
Frédéric Péters | 40fe3f835f | |
Frédéric Péters | ab9b2f110c | |
Frédéric Péters | a72cc63a7f | |
Frédéric Péters | 3a6215856f | |
Frédéric Péters | 2a287e61b9 | |
Frédéric Péters | f934f78403 | |
Frédéric Péters | 901db27863 | |
Frédéric Péters | 72449ed00d | |
Frédéric Péters | c3fc205a85 | |
Emmanuel Cazenave | 7e8e50816f | |
Emmanuel Cazenave | 6432625ff2 | |
Frédéric Péters | aec0edb0c8 | |
Frédéric Péters | 250ef2e74a | |
Nicolas Roche | 36c0e69cb1 |
|
@ -1,2 +1,6 @@
|
|||
# trivial: apply black
|
||||
ce7f2dd5000cf1eb462ae18aeeb5ab66913b452f
|
||||
# trivial: apply isort & pyupgrade
|
||||
250ef2e74ae674f7039318787ba85b63f2825c7d
|
||||
# misc: apply double-quote-string-fixer (#79788)
|
||||
103dff03cb7862a6dde22b1a358a7af7f86424fc
|
||||
|
|
|
@ -1,8 +1,22 @@
|
|||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: double-quote-string-fixer
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 20.8b1
|
||||
rev: 22.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
args: ['--target-version', 'py37', '--skip-string-normalization', '--line-length', '110']
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
args: ['--profile', 'black', '--line-length', '110']
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.1.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ['--keep-percent-format', '--py37-plus']
|
||||
|
|
|
@ -23,10 +23,18 @@ pipeline {
|
|||
stage('Packaging') {
|
||||
steps {
|
||||
script {
|
||||
if (env.JOB_NAME == 'welco' && env.GIT_BRANCH == 'origin/main') {
|
||||
sh 'sudo -H -u eobuilder /usr/local/bin/eobuilder welco'
|
||||
env.SHORT_JOB_NAME=sh(
|
||||
returnStdout: true,
|
||||
// given JOB_NAME=gitea/project/PR-46, returns project
|
||||
// given JOB_NAME=project/main, returns project
|
||||
script: '''
|
||||
echo "${JOB_NAME}" | sed "s/gitea\\///" | awk -F/ '{print $1}'
|
||||
'''
|
||||
).trim()
|
||||
if (env.GIT_BRANCH == 'main' || env.GIT_BRANCH == 'origin/main') {
|
||||
sh "sudo -H -u eobuilder /usr/local/bin/eobuilder -d bullseye,bookworm ${SHORT_JOB_NAME}"
|
||||
} else if (env.GIT_BRANCH.startsWith('hotfix/')) {
|
||||
sh "sudo -H -u eobuilder /usr/local/bin/eobuilder --branch ${env.GIT_BRANCH} --hotfix welco"
|
||||
sh "sudo -H -u eobuilder /usr/local/bin/eobuilder -d bullseye,bookworm --branch ${env.GIT_BRANCH} --hotfix ${SHORT_JOB_NAME}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
README
13
README
|
@ -44,8 +44,17 @@ black is used to format the code, using thoses parameters:
|
|||
|
||||
black --target-version py37 --skip-string-normalization --line-length 110
|
||||
|
||||
There is .pre-commit-config.yaml to use pre-commit to automatically run black
|
||||
before commits. (execute `pre-commit install` to install the git hook.)
|
||||
isort is used to format the imports, using those parameters:
|
||||
|
||||
isort --profile black --line-length 110
|
||||
|
||||
pyupgrade is used to automatically upgrade syntax, using those parameters:
|
||||
|
||||
pyupgrade --keep-percent-format --py37-plus
|
||||
|
||||
There is .pre-commit-config.yaml to use pre-commit to automatically run black,
|
||||
isort and pyupgrade before commits. (execute `pre-commit install` to install
|
||||
the git hook.)
|
||||
|
||||
|
||||
License
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
9
|
|
@ -2,13 +2,13 @@ Source: welco
|
|||
Maintainer: Frederic Peters <fpters@entrouvert.com>
|
||||
Section: python
|
||||
Priority: optional
|
||||
Build-Depends: python3-setuptools, python3-all, debhelper (>= 9), python3-django, dh-python, dh-systemd
|
||||
Build-Depends: python3-setuptools, python3-all, debhelper-compat (= 12), python3-django, dh-python
|
||||
Standards-Version: 3.9.6
|
||||
|
||||
Package: python3-welco
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, ${python3:Depends},
|
||||
python3-django (>= 1:1.11),
|
||||
python3-django (>= 2:2.2),
|
||||
python3-gadjo,
|
||||
python3-requests (>= 2.11),
|
||||
python3-django-haystack (>= 2.4.0),
|
||||
|
@ -25,6 +25,7 @@ Depends: ${misc:Depends},
|
|||
python3-django-tenant-schemas,
|
||||
python3-psycopg2,
|
||||
python3-django-mellon,
|
||||
python3-uwsgidecorators,
|
||||
python3-xstatic-select2,
|
||||
uwsgi,
|
||||
uwsgi-plugin-python3,
|
||||
|
|
|
@ -5,7 +5,7 @@ export PYBUILD_NAME=welco
|
|||
export PYBUILD_DISABLE=test
|
||||
|
||||
%:
|
||||
dh $@ --with python3,systemd --buildsystem=pybuild
|
||||
dh $@ --with python3 --buildsystem=pybuild
|
||||
|
||||
override_dh_install:
|
||||
dh_install
|
||||
|
|
|
@ -9,6 +9,10 @@ http-socket = /run/welco/welco.sock
|
|||
chmod-socket = 666
|
||||
vacuum = true
|
||||
|
||||
spooler-processes = 3
|
||||
spooler-python-import = hobo.provisionning.spooler
|
||||
spooler-max-tasks = 20
|
||||
|
||||
master = true
|
||||
processes = 5
|
||||
harakiri = 120
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
SHELL=/bin/sh
|
||||
PATH=/usr/sbin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
*/10 6-22 * * * welco /usr/bin/welco-manage tenant_command feed_mail_maarch --all-tenants
|
||||
*/10 6-22 * * * welco /usr/bin/welco-manage tenant_command feed_mail_maarch --all-tenants -v0
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
/sbin/runuser -u welco /usr/bin/welco-manage -- tenant_command clearsessions --all-tenants
|
||||
/sbin/runuser -u welco /usr/bin/welco-manage -- tenant_command clearsessions --all-tenants -v0
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/etc/welco
|
||||
/usr/lib/welco
|
||||
/var/lib/welco/collectstatic
|
||||
/var/lib/welco/spooler
|
||||
/var/lib/welco/tenants
|
||||
/var/log/welco
|
||||
|
|
|
@ -38,6 +38,7 @@ GROUP=$NAME
|
|||
DAEMON_ARGS=${DAEMON_ARGS:-"--pidfile=$PIDFILE
|
||||
--uid $USER --gid $GROUP
|
||||
--ini /etc/$NAME/uwsgi.ini
|
||||
--spooler /var/lib/$NAME/spooler/
|
||||
--daemonize /var/log/uwsgi.$NAME.log"}
|
||||
|
||||
# Load the VERBOSE setting and other rcS variables
|
||||
|
|
|
@ -20,6 +20,7 @@ case "$1" in
|
|||
# ensure dirs ownership
|
||||
chown $USER:$GROUP /var/log/$NAME
|
||||
chown $USER:$GROUP /var/lib/$NAME/collectstatic
|
||||
chown $USER:$GROUP /var/lib/$NAME/spooler
|
||||
chown $USER:$GROUP /var/lib/$NAME/tenants
|
||||
# create a secret file
|
||||
SECRET_FILE=$CONFIG_DIR/secret
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
[Unit]
|
||||
Description=Welco
|
||||
After=network.target syslog.target postgresql.service
|
||||
After=network.target postgresql.service
|
||||
Wants=postgresql.service
|
||||
|
||||
[Service]
|
||||
SyslogIdentifier=uwsgi/%p
|
||||
Environment=WELCO_SETTINGS_FILE=/usr/lib/%p/debian_config.py
|
||||
Environment=LANG=C.UTF-8
|
||||
User=%p
|
||||
Group=%p
|
||||
ExecStartPre=/usr/bin/welco-manage migrate_schemas --noinput --verbosity 1
|
||||
ExecStartPre=/usr/bin/welco-manage collectstatic --noinput
|
||||
ExecStart=/usr/bin/uwsgi --ini /etc/%p/uwsgi.ini
|
||||
ExecStartPre=/bin/mkdir -p /var/lib/welco/spooler/%m/
|
||||
ExecStart=/usr/bin/uwsgi --ini /etc/%p/uwsgi.ini --spooler /var/lib/welco/spooler/%m/
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillSignal=SIGQUIT
|
||||
TimeoutStartSec=0
|
||||
|
@ -18,7 +20,6 @@ PrivateTmp=true
|
|||
Restart=on-failure
|
||||
RuntimeDirectory=welco
|
||||
Type=notify
|
||||
StandardError=syslog
|
||||
NotifyAccess=all
|
||||
|
||||
[Install]
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "welco.settings")
|
||||
if __name__ == '__main__':
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'welco.settings')
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
|
|
20
setup.py
20
setup.py
|
@ -1,15 +1,14 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from setuptools.command.install_lib import install_lib as _install_lib
|
||||
from distutils.cmd import Command
|
||||
from distutils.command.build import build as _build
|
||||
from distutils.command.sdist import sdist
|
||||
from distutils.cmd import Command
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
from setuptools.command.install_lib import install_lib as _install_lib
|
||||
|
||||
|
||||
class eo_sdist(sdist):
|
||||
|
@ -29,7 +28,7 @@ def get_version():
|
|||
tag exists, take 0.0- and add the length of the commit log.
|
||||
"""
|
||||
if os.path.exists('VERSION'):
|
||||
with open('VERSION', 'r') as v:
|
||||
with open('VERSION') as v:
|
||||
return v.read()
|
||||
if os.path.exists('.git'):
|
||||
p = subprocess.Popen(
|
||||
|
@ -107,15 +106,14 @@ setup(
|
|||
'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
],
|
||||
install_requires=[
|
||||
'django>=1.11,<2.3',
|
||||
'django>=2.2,<3.3',
|
||||
'gadjo',
|
||||
'django-ckeditor<4.5.4',
|
||||
'django-haystack<2.8',
|
||||
'django-taggit',
|
||||
'djangorestframework>=3.3,<3.10',
|
||||
'django-haystack<3.2.2',
|
||||
'django-taggit<3.1.1',
|
||||
'djangorestframework>=3.3,<3.15',
|
||||
'requests',
|
||||
'whoosh',
|
||||
'XStatic-Select2',
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
# 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 pytest
|
||||
import django_webtest
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
# 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 unittest import mock
|
||||
|
||||
import httmock
|
||||
import mock
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.core.management.base import CommandError
|
||||
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
# 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 httmock
|
||||
import json
|
||||
import requests
|
||||
from webtest import Upload
|
||||
|
||||
import httmock
|
||||
import requests
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.files.base import ContentFile
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
from webtest import Upload
|
||||
|
||||
from welco.sources.mail.models import Mail
|
||||
|
||||
|
@ -74,11 +74,11 @@ def test_qualification_save_view(settings, app, db):
|
|||
def response_get(url, request):
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = {
|
||||
"err": 0,
|
||||
"data": [
|
||||
'err': 0,
|
||||
'data': [
|
||||
{
|
||||
"title": "Foo",
|
||||
"slug": "foo",
|
||||
'title': 'Foo',
|
||||
'slug': 'foo',
|
||||
}
|
||||
],
|
||||
}
|
||||
|
@ -134,9 +134,9 @@ def test_reject_view(settings, app, user):
|
|||
|
||||
@httmock.urlmatch(netloc='maarch.example.net', path='/rest/res/resource/status', method='PUT')
|
||||
def response_ok(url, request):
|
||||
assert json.loads(force_text(request.body)) == {'status': 'FOO', 'resId': ['42']}
|
||||
assert json.loads(force_str(request.body)) == {'status': 'FOO', 'resId': ['42']}
|
||||
headers = {'content-type': 'application/json'}
|
||||
content = {"maarch_say": "ok"}
|
||||
content = {'maarch_say': 'ok'}
|
||||
return httmock.response(200, content, headers)
|
||||
|
||||
with httmock.HTTMock(response_ok):
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
# 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 httmock
|
||||
import mock
|
||||
import pytest
|
||||
from unittest import mock
|
||||
|
||||
import httmock
|
||||
import pytest
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
|
@ -201,7 +201,7 @@ def test_menu_json_view(app, user, mail_group, phone_group, counter_group, kb_gr
|
|||
app.set_user(user.username)
|
||||
resp = app.get('/menu.json', status=200)
|
||||
assert resp.content_type == 'application/json'
|
||||
assert sorted([x['label'] for x in resp.json]) == ['Call Center', 'Counter', 'Knowledge Base', 'Mails']
|
||||
assert sorted(x['label'] for x in resp.json) == ['Call Center', 'Counter', 'Knowledge Base', 'Mails']
|
||||
|
||||
resp = app.get('/menu.json?callback=foo', status=200)
|
||||
assert resp.content_type == 'application/javascript'
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
# 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 mock
|
||||
import pytest
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from django.test import override_settings
|
||||
|
||||
from welco.forms import QualificationForm
|
||||
|
|
|
@ -17,14 +17,12 @@
|
|||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
from httmock import urlmatch, HTTMock
|
||||
from django.utils.encoding import force_str
|
||||
from httmock import HTTMock, urlmatch
|
||||
|
||||
|
||||
class BaseMock(object):
|
||||
class BaseMock:
|
||||
def __init__(self, netloc):
|
||||
self.netloc = netloc
|
||||
self.clear()
|
||||
|
@ -51,7 +49,7 @@ class BaseMock(object):
|
|||
|
||||
class MaarchMock(BaseMock):
|
||||
def list_endpoint(self, url, request):
|
||||
self.requests.append(('list_endpoint', url, request, json.loads(force_text(request.body))))
|
||||
self.requests.append(('list_endpoint', url, request, json.loads(force_str(request.body))))
|
||||
return {
|
||||
'content': json.dumps(self.next_response()),
|
||||
'headers': {
|
||||
|
@ -63,13 +61,13 @@ class MaarchMock(BaseMock):
|
|||
list_endpoint.path = '^/rest/res/list$'
|
||||
|
||||
def update_external_infos(self, url, request):
|
||||
self.requests.append(('update_external_infos', url, request, json.loads(force_text(request.body))))
|
||||
self.requests.append(('update_external_infos', url, request, json.loads(force_str(request.body))))
|
||||
return json.dumps({})
|
||||
|
||||
update_external_infos.path = '^/rest/res/externalInfos$'
|
||||
|
||||
def update_status(self, url, request):
|
||||
self.requests.append(('update_status', url, request, json.loads(force_text(request.body))))
|
||||
self.requests.append(('update_status', url, request, json.loads(force_str(request.body))))
|
||||
return {
|
||||
'content': json.dumps(self.next_response()),
|
||||
'headers': {
|
||||
|
@ -81,7 +79,7 @@ class MaarchMock(BaseMock):
|
|||
update_status.path = '^/rest/res/resource/status$'
|
||||
|
||||
def post_courrier(self, url, request):
|
||||
self.requests.append(('post_courrier', url, request, json.loads(force_text(request.body))))
|
||||
self.requests.append(('post_courrier', url, request, json.loads(force_str(request.body))))
|
||||
|
||||
post_courrier.path = '^/rest/res$'
|
||||
|
||||
|
@ -177,8 +175,10 @@ PDF_MOCK = b'%PDF-1.4 ...'
|
|||
|
||||
def test_feed(settings, app, maarch, wcs, user):
|
||||
import base64
|
||||
from django.core.management import call_command
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.management import call_command
|
||||
|
||||
from welco.sources.mail.models import Mail
|
||||
|
||||
app.set_user(user.username)
|
||||
|
@ -194,7 +194,7 @@ def test_feed(settings, app, maarch, wcs, user):
|
|||
'resources': [
|
||||
{
|
||||
'res_id': 1,
|
||||
'fileBase64Content': force_text(base64.b64encode(PDF_MOCK)),
|
||||
'fileBase64Content': force_str(base64.b64encode(PDF_MOCK)),
|
||||
}
|
||||
],
|
||||
}
|
||||
|
|
|
@ -18,11 +18,9 @@ import json
|
|||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from django.urls import reverse
|
||||
from django.test import override_settings
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.timezone import now, timedelta
|
||||
|
||||
from welco.sources.phone import models
|
||||
|
@ -166,10 +164,10 @@ def test_current_calls(user, client):
|
|||
assert response['content-type'] == 'application/json'
|
||||
payload = response.json()
|
||||
assert isinstance(payload, dict)
|
||||
assert set(payload.keys()) == set(['err', 'data'])
|
||||
assert set(payload.keys()) == {'err', 'data'}
|
||||
assert payload['err'] == 0
|
||||
data = payload['data']
|
||||
assert set(data.keys()) == set(['calls', 'lines', 'all-lines'])
|
||||
assert set(data.keys()) == {'calls', 'lines', 'all-lines'}
|
||||
assert isinstance(data['calls'], list)
|
||||
assert isinstance(data['lines'], list)
|
||||
assert isinstance(data['all-lines'], list)
|
||||
|
@ -177,14 +175,14 @@ def test_current_calls(user, client):
|
|||
assert len(data['lines']) == 5
|
||||
assert len(data['all-lines']) == 10
|
||||
for call in data['calls']:
|
||||
assert set(call.keys()) <= set(['caller', 'callee', 'start', 'data'])
|
||||
assert isinstance(call['caller'], six.string_types)
|
||||
assert isinstance(call['callee'], six.string_types)
|
||||
assert isinstance(call['start'], six.string_types)
|
||||
assert set(call.keys()) <= {'caller', 'callee', 'start', 'data'}
|
||||
assert isinstance(call['caller'], str)
|
||||
assert isinstance(call['callee'], str)
|
||||
assert isinstance(call['start'], str)
|
||||
if 'data' in call:
|
||||
assert isinstance(call['data'], dict)
|
||||
assert len([call for call in data['lines'] if isinstance(call, six.string_types)]) == 5
|
||||
assert len([call for call in data['all-lines'] if isinstance(call, six.string_types)]) == 10
|
||||
assert len([call for call in data['lines'] if isinstance(call, str)]) == 5
|
||||
assert len([call for call in data['all-lines'] if isinstance(call, str)]) == 10
|
||||
|
||||
# unregister user to all remaining lines
|
||||
for number in range(0, 5):
|
||||
|
@ -194,9 +192,9 @@ def test_current_calls(user, client):
|
|||
assert response['content-type'] == 'application/json'
|
||||
payload = response.json()
|
||||
assert isinstance(payload, dict)
|
||||
assert set(payload.keys()) == set(['err', 'data'])
|
||||
assert set(payload.keys()) == {'err', 'data'}
|
||||
assert payload['err'] == 0
|
||||
assert set(payload['data'].keys()) == set(['calls', 'lines', 'all-lines'])
|
||||
assert set(payload['data'].keys()) == {'calls', 'lines', 'all-lines'}
|
||||
assert len(payload['data']['calls']) == 0
|
||||
assert len(payload['data']['lines']) == 0
|
||||
assert len(payload['data']['all-lines']) == 10
|
||||
|
@ -229,18 +227,18 @@ def test_phone_zone(user, client):
|
|||
client.login(username='toto', password='toto')
|
||||
response = client.get(reverse('phone-zone'))
|
||||
assert response.status_code == 200
|
||||
assert 'You do not have a phoneline configured' in force_text(response.content)
|
||||
assert 'You do not have a phoneline configured' in force_str(response.content)
|
||||
|
||||
models.PhoneLine.take(callee='102', user=user)
|
||||
|
||||
response = client.get(reverse('phone-zone'))
|
||||
assert response.status_code == 200
|
||||
assert 'You do not have a phoneline configured' not in force_text(response.content)
|
||||
assert '<li>102' in force_text(response.content)
|
||||
assert 'data-callee="102"' in force_text(response.content)
|
||||
assert 'You do not have a phoneline configured' not in force_str(response.content)
|
||||
assert '<li>102' in force_str(response.content)
|
||||
assert 'data-callee="102"' in force_str(response.content)
|
||||
currents = re.search(
|
||||
'<div id="source-mainarea" ' 'data-current-calls="/api/phone/current-calls/">' '(.*?)</div>',
|
||||
force_text(response.content),
|
||||
force_str(response.content),
|
||||
flags=re.DOTALL,
|
||||
)
|
||||
assert currents.group(1).strip() == ''
|
||||
|
@ -251,7 +249,7 @@ def test_phone_zone(user, client):
|
|||
assert response.status_code == 200
|
||||
response = client.get(reverse('phone-zone'))
|
||||
assert response.status_code == 200
|
||||
assert '<h1>Current Call: <strong>003369999999</strong></h1>' in force_text(response.content)
|
||||
assert '<h1>Current Call: <strong>003369999999</strong></h1>' in force_str(response.content)
|
||||
|
||||
# simulate a mellon user
|
||||
session = client.session
|
||||
|
@ -259,19 +257,19 @@ def test_phone_zone(user, client):
|
|||
session.save()
|
||||
response = client.get(reverse('phone-zone'))
|
||||
assert response.status_code == 200
|
||||
assert 'agent007' not in force_text(response.content)
|
||||
assert 'data-callee="agent007"' not in force_text(response.content)
|
||||
assert '<li>102' in force_text(response.content)
|
||||
assert 'data-callee="102"' in force_text(response.content)
|
||||
assert 'agent007' not in force_str(response.content)
|
||||
assert 'data-callee="agent007"' not in force_str(response.content)
|
||||
assert '<li>102' in force_str(response.content)
|
||||
assert 'data-callee="102"' in force_str(response.content)
|
||||
|
||||
with override_settings(PHONE_AUTOTAKE_MELLON_USERNAME=True):
|
||||
response = client.get(reverse('phone-zone'))
|
||||
assert response.status_code == 200
|
||||
assert '<h1>Current Call: <strong>003369999999</strong></h1>' in force_text(response.content)
|
||||
assert 'agent007' in force_text(response.content)
|
||||
assert 'data-callee="agent007"' in force_text(response.content)
|
||||
assert '<li>102' in force_text(response.content)
|
||||
assert 'data-callee="102"' in force_text(response.content)
|
||||
assert '<h1>Current Call: <strong>003369999999</strong></h1>' in force_str(response.content)
|
||||
assert 'agent007' in force_str(response.content)
|
||||
assert 'data-callee="agent007"' in force_str(response.content)
|
||||
assert '<li>102' in force_str(response.content)
|
||||
assert 'data-callee="102"' in force_str(response.content)
|
||||
|
||||
|
||||
def test_call_expiration(user, client):
|
||||
|
|
11
tox.ini
11
tox.ini
|
@ -1,5 +1,7 @@
|
|||
[tox]
|
||||
envlist = py3-django22-black-coverage-pylint
|
||||
envlist =
|
||||
py3-django32-drf314
|
||||
py3-django32-black-coverage-pylint-drf312
|
||||
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/welco/{env:BRANCH_NAME:}
|
||||
|
||||
[testenv]
|
||||
|
@ -12,7 +14,7 @@ setenv =
|
|||
fast: FAST=--nomigrations
|
||||
coverage: COVERAGE=--junitxml=junit-{envname}.xml --cov-report xml --cov-report html --cov=welco/
|
||||
deps =
|
||||
django22: django>=2.2,<2.3
|
||||
django32: django>=3.2,<3.3
|
||||
pytest-cov
|
||||
pytest-django
|
||||
pytest!=5.3.3
|
||||
|
@ -20,13 +22,16 @@ deps =
|
|||
mock<4
|
||||
httmock
|
||||
python-dateutil
|
||||
pylint
|
||||
pylint<3
|
||||
astroid<3
|
||||
pylint-django
|
||||
django-webtest
|
||||
pyquery
|
||||
lxml
|
||||
git+https://git.entrouvert.org/debian/django-ckeditor.git
|
||||
black: pre-commit
|
||||
drf312: djangorestframework>=3.12,<3.13
|
||||
drf314: djangorestframework>=3.14,<3.15
|
||||
commands =
|
||||
pylint: ./pylint.sh welco/
|
||||
py.test {env:COVERAGE:} {posargs:tests/}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf.urls import include, url
|
||||
from django.urls import include, re_path
|
||||
|
||||
|
||||
def register_urls(urlpatterns):
|
||||
|
@ -25,9 +25,9 @@ def register_urls(urlpatterns):
|
|||
if hasattr(app, 'get_before_urls'):
|
||||
urls = app.get_before_urls()
|
||||
if urls:
|
||||
pre_urls.append(url('^', include(urls)))
|
||||
pre_urls.append(re_path('^', include(urls)))
|
||||
if hasattr(app, 'get_after_urls'):
|
||||
urls = app.get_after_urls()
|
||||
if urls:
|
||||
post_urls.append(url('^', include(urls)))
|
||||
post_urls.append(re_path('^', include(urls)))
|
||||
return pre_urls + urlpatterns + post_urls
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _, pgettext_lazy
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import pgettext_lazy
|
||||
|
||||
DEFAULT_TITLE_CHOICES = (
|
||||
('', ''),
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
import json
|
||||
import logging
|
||||
import random
|
||||
import requests
|
||||
import time
|
||||
|
||||
import requests
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
@ -27,14 +27,14 @@ from django.core.exceptions import PermissionDenied
|
|||
from django.http import HttpResponse
|
||||
from django.template import RequestContext
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import TemplateView, FormView
|
||||
from django.views.generic import FormView, TemplateView
|
||||
|
||||
from welco.utils import get_wcs_data, sign_url
|
||||
|
||||
from .forms import ContactAddForm
|
||||
|
||||
|
||||
class HomeZone(object):
|
||||
class HomeZone:
|
||||
def __init__(self, request):
|
||||
self.request = request
|
||||
|
||||
|
@ -47,7 +47,7 @@ class ContactsZone(TemplateView):
|
|||
template_name = 'contacts/zone.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ContactsZone, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['source_pk'] = self.request.GET.get('source_pk')
|
||||
if 'source_pk' in self.request.GET:
|
||||
source_class = ContentType.objects.get(id=self.request.GET['source_type']).model_class()
|
||||
|
@ -68,7 +68,7 @@ zone = csrf_exempt(ContactsZone.as_view())
|
|||
|
||||
|
||||
def search_json(request):
|
||||
user_groups = set([x.name for x in request.user.groups.all()])
|
||||
user_groups = {x.name for x in request.user.groups.all()}
|
||||
for channel in settings.CHANNEL_ROLES:
|
||||
channel_groups = set(settings.CHANNEL_ROLES[channel])
|
||||
if user_groups.intersection(channel_groups):
|
||||
|
@ -104,7 +104,7 @@ class ContactDetailFragmentView(TemplateView):
|
|||
template_name = 'contacts/contact_detail_fragment.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ContactDetailFragmentView, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
user_id = self.kwargs.get('slug').split('-')[-1]
|
||||
user_details = get_wcs_data('api/users/%s/' % user_id)
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .utils import get_wcs_options
|
||||
|
||||
|
@ -24,7 +24,7 @@ class QualificationForm(forms.Form):
|
|||
formdef_reference = forms.CharField(label=_('Associated Form'))
|
||||
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
super(QualificationForm, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
params = {'backoffice-submission': 'on'}
|
||||
if hasattr(user, 'saml_identifiers') and user.saml_identifiers.exists():
|
||||
params['NameID'] = user.saml_identifiers.first().name_id
|
||||
|
|
|
@ -38,4 +38,4 @@ class PageForm(forms.ModelForm):
|
|||
i += 1
|
||||
slug = '%s-%s' % (base_slug, i)
|
||||
self.instance.slug = slug
|
||||
return super(PageForm, self).save(commit=commit)
|
||||
return super().save(commit=commit)
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import ckeditor.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import taggit.managers
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -14,11 +14,10 @@
|
|||
# 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.urls import reverse
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from ckeditor.fields import RichTextField
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
# 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.utils.html import strip_tags
|
||||
from django.utils.six.moves.html_parser import HTMLParser
|
||||
import html
|
||||
|
||||
from django.utils.html import strip_tags
|
||||
from haystack import indexes
|
||||
|
||||
from .models import Page
|
||||
|
@ -33,7 +33,7 @@ class PageIndex(indexes.SearchIndex, indexes.Indexable):
|
|||
return Page
|
||||
|
||||
def prepare_text(self, obj):
|
||||
return obj.title + ' ' + self.prepare_tags(obj) + ' ' + HTMLParser().unescape(strip_tags(obj.content))
|
||||
return obj.title + ' ' + self.prepare_tags(obj) + ' ' + html.unescape(strip_tags(obj.content))
|
||||
|
||||
def prepare_text_auto(self, obj):
|
||||
return self.prepare_text(obj)
|
||||
|
|
|
@ -20,20 +20,19 @@ from django import template
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.urls import reverse_lazy
|
||||
from django.db.models import Count
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.template import RequestContext
|
||||
from django.urls import reverse_lazy
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import DetailView, CreateView, UpdateView, ListView, DeleteView, TemplateView
|
||||
|
||||
from django.views.generic import CreateView, DeleteView, DetailView, ListView, TemplateView, UpdateView
|
||||
from haystack.forms import SearchForm
|
||||
from haystack.generic_views import SearchView
|
||||
from haystack.query import SearchQuerySet
|
||||
from taggit.models import Tag
|
||||
|
||||
from .models import Page
|
||||
from .forms import PageForm
|
||||
from .models import Page
|
||||
|
||||
|
||||
def check_user_perms(user, access=False):
|
||||
|
@ -42,7 +41,7 @@ def check_user_perms(user, access=False):
|
|||
allowed_roles.extend(settings.KB_ACCESS_ROLES)
|
||||
if settings.KB_ROLE:
|
||||
allowed_roles.append(settings.KB_ROLE) # legacy
|
||||
user_groups = set([x.name for x in user.groups.all()])
|
||||
user_groups = {x.name for x in user.groups.all()}
|
||||
return user_groups.intersection(allowed_roles)
|
||||
|
||||
|
||||
|
@ -56,10 +55,10 @@ class PageListView(ListView):
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
check_request_perms(request, access=True)
|
||||
return super(PageListView, self).dispatch(request, *args, **kwargs)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(PageListView, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['form'] = SearchForm()
|
||||
context['can_manage'] = check_user_perms(self.request.user)
|
||||
return context
|
||||
|
@ -74,7 +73,7 @@ class PageAddView(CreateView):
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
check_request_perms(request)
|
||||
return super(PageAddView, self).dispatch(request, *args, **kwargs)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
page_add = login_required(PageAddView.as_view())
|
||||
|
@ -86,7 +85,7 @@ class PageEditView(UpdateView):
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
check_request_perms(request)
|
||||
return super(PageEditView, self).dispatch(request, *args, **kwargs)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
page_edit = login_required(PageEditView.as_view())
|
||||
|
@ -97,10 +96,10 @@ class PageDetailView(DetailView):
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
check_request_perms(request, access=True)
|
||||
return super(PageDetailView, self).dispatch(request, *args, **kwargs)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(PageDetailView, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['can_manage'] = check_user_perms(self.request.user)
|
||||
return context
|
||||
|
||||
|
@ -122,7 +121,7 @@ class PageDeleteView(DeleteView):
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
check_request_perms(request)
|
||||
return super(PageDeleteView, self).dispatch(request, *args, **kwargs)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
page_delete = login_required(PageDeleteView.as_view())
|
||||
|
@ -134,7 +133,7 @@ class PageSearchView(SearchView):
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
check_request_perms(request, access=True)
|
||||
return super(PageSearchView, self).dispatch(request, *args, **kwargs)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
page_search = login_required(PageSearchView.as_view())
|
||||
|
@ -144,7 +143,7 @@ class KbZone(TemplateView):
|
|||
template_name = 'kb/zone.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(KbZone, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['source_pk'] = self.request.GET.get('source_pk')
|
||||
context['form'] = SearchForm()
|
||||
context['tags'] = (
|
||||
|
@ -190,7 +189,7 @@ def page_search_json(request):
|
|||
return response
|
||||
|
||||
|
||||
class HomeZone(object):
|
||||
class HomeZone:
|
||||
def __init__(self, request):
|
||||
self.request = request
|
||||
|
||||
|
|
|
@ -14,16 +14,15 @@
|
|||
# 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.urls import reverse
|
||||
import ckeditor.widgets
|
||||
from django.forms.utils import flatatt
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.encoding import force_text
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.html import conditional_escape
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import get_language
|
||||
|
||||
import ckeditor.widgets
|
||||
|
||||
|
||||
def ckeditor_render(self, name, value, attrs=None, renderer=None):
|
||||
if value is None:
|
||||
|
@ -42,7 +41,7 @@ def ckeditor_render(self, name, value, attrs=None, renderer=None):
|
|||
|
||||
# Force to text to evaluate possible lazy objects
|
||||
external_plugin_resources = [
|
||||
[force_text(a), force_text(b), force_text(c)] for a, b, c in self.external_plugin_resources
|
||||
[force_str(a), force_str(b), force_str(c)] for a, b, c in self.external_plugin_resources
|
||||
]
|
||||
|
||||
return mark_safe(
|
||||
|
@ -50,7 +49,7 @@ def ckeditor_render(self, name, value, attrs=None, renderer=None):
|
|||
'ckeditor/widget.html',
|
||||
{
|
||||
'final_attrs': flatatt(final_attrs),
|
||||
'value': conditional_escape(force_text(value)),
|
||||
'value': conditional_escape(force_str(value)),
|
||||
'id': final_attrs['id'],
|
||||
'config': ckeditor.widgets.json_encode(self.config),
|
||||
'external_plugin_resources': ckeditor.widgets.json_encode(external_plugin_resources),
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
# 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.contenttypes.models import ContentType
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.urls import reverse
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from welco.utils import get_wcs_formdef_details, push_wcs_formdata, get_wcs_services
|
||||
from welco.utils import get_wcs_formdef_details, get_wcs_services, push_wcs_formdata
|
||||
|
||||
|
||||
class Association(models.Model):
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Django settings for welco project.
|
||||
|
||||
|
@ -11,8 +9,9 @@ https://docs.djangoproject.com/en/1.7/ref/settings/
|
|||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.conf import global_settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from welco.qualif.models import Association
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
# 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 django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^ajax/counter/zone/$', views.zone, name='counter-zone'),
|
||||
path('ajax/counter/zone/', views.zone, name='counter-zone'),
|
||||
]
|
||||
|
|
|
@ -18,17 +18,17 @@ import json
|
|||
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.http import HttpResponse
|
||||
from django.template import RequestContext
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponse
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from .models import CounterPresence
|
||||
|
||||
|
||||
class Home(object):
|
||||
class Home:
|
||||
source_key = 'counter'
|
||||
|
||||
def __init__(self, request, **kwargs):
|
||||
|
@ -46,7 +46,7 @@ class CounterZone(TemplateView):
|
|||
template_name = 'welco/counter_home.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(CounterZone, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['source_type'] = ContentType.objects.get_for_model(CounterPresence)
|
||||
new_source = CounterPresence()
|
||||
new_source.save()
|
||||
|
|
|
@ -26,9 +26,10 @@ class AppConfig(django.apps.AppConfig):
|
|||
return urls.urlpatterns
|
||||
|
||||
def ready(self):
|
||||
from welco.qualif.models import Association
|
||||
from django.db.models import signals
|
||||
|
||||
from welco.qualif.models import Association
|
||||
|
||||
signals.post_save.connect(self.association_post_save, sender=Association)
|
||||
|
||||
def association_post_save(self, sender, instance, **kwargs):
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class MailQualificationForm(forms.Form):
|
||||
|
|
|
@ -15,12 +15,10 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import base64
|
||||
|
||||
from dateutil.parser import parse as parse_datetime
|
||||
from django.utils import six
|
||||
from django.utils.six.moves.urllib import parse as urlparse
|
||||
import urllib.parse
|
||||
|
||||
import requests
|
||||
from dateutil.parser import parse as parse_datetime
|
||||
from requests.adapters import HTTPAdapter
|
||||
from requests.packages.urllib3.util.retry import Retry
|
||||
|
||||
|
@ -29,7 +27,7 @@ class MaarchError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class MaarchCourrier(object):
|
||||
class MaarchCourrier:
|
||||
url = None
|
||||
username = None
|
||||
password = None
|
||||
|
@ -44,7 +42,7 @@ class MaarchCourrier(object):
|
|||
def __repr__(self):
|
||||
return '<MaarchCourrier url:%s>' % self.url
|
||||
|
||||
class Courrier(object):
|
||||
class Courrier:
|
||||
content = None
|
||||
format = None
|
||||
status = None
|
||||
|
@ -89,7 +87,7 @@ class MaarchCourrier(object):
|
|||
data = {key: self.__dict__[key] for key in self.__dict__ if key not in excluded_keys}
|
||||
if data:
|
||||
for key, value in data.items():
|
||||
if isinstance(value, six.string_types):
|
||||
if isinstance(value, str):
|
||||
d.append({'column': key, 'value': value, 'type': 'string'})
|
||||
elif isinstance(value, int):
|
||||
d.append({'column': key, 'value': str(value), 'type': 'int'})
|
||||
|
@ -153,19 +151,19 @@ class MaarchCourrier(object):
|
|||
|
||||
@property
|
||||
def list_url(self):
|
||||
return urlparse.urljoin(self.url, 'rest/res/list')
|
||||
return urllib.parse.urljoin(self.url, 'rest/res/list')
|
||||
|
||||
@property
|
||||
def update_external_infos_url(self):
|
||||
return urlparse.urljoin(self.url, 'rest/res/externalInfos')
|
||||
return urllib.parse.urljoin(self.url, 'rest/res/externalInfos')
|
||||
|
||||
@property
|
||||
def update_status_url(self):
|
||||
return urlparse.urljoin(self.url, 'rest/res/resource/status')
|
||||
return urllib.parse.urljoin(self.url, 'rest/res/resource/status')
|
||||
|
||||
@property
|
||||
def post_courrier_url(self):
|
||||
return urlparse.urljoin(self.url, 'rest/res')
|
||||
return urllib.parse.urljoin(self.url, 'rest/res')
|
||||
|
||||
def get_courriers(self, clause, fields=None, limit=None, include_file=False, order_by=None):
|
||||
if fields:
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
# 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 optparse import make_option
|
||||
import os
|
||||
from optparse import make_option
|
||||
|
||||
from django.core.files import File
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from ...models import Mail
|
||||
|
@ -35,7 +35,7 @@ class Command(BaseCommand):
|
|||
continue
|
||||
if not open(filepath).read(5) == '%PDF-':
|
||||
continue
|
||||
mail = Mail(content=File(open(filepath)))
|
||||
mail = Mail(content=ContentFile(open(filepath).read(), name=os.path.basename(filepath)))
|
||||
mail.scanner_category = kwargs.get('category')
|
||||
mail.save()
|
||||
count += 1
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
# 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 optparse import make_option
|
||||
import os
|
||||
from optparse import make_option
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
|
||||
from ...models import Mail
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
@ -15,17 +15,17 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import re
|
||||
import requests
|
||||
import subprocess
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.urls import reverse
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from welco.qualif.models import Association
|
||||
from welco.utils import get_wcs_data
|
||||
|
|
|
@ -14,17 +14,17 @@
|
|||
# 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 django.urls import path, re_path
|
||||
|
||||
from .views import viewer, feeder, qualification_save, edit_note, note, reject, mail_count, mail_response
|
||||
from .views import edit_note, feeder, mail_count, mail_response, note, qualification_save, reject, viewer
|
||||
|
||||
urlpatterns = [
|
||||
url('viewer/$', viewer, name='mail-viewer'),
|
||||
url('mail/feeder/$', feeder, name='mail-feeder'),
|
||||
url(r'^ajax/mail/reject$', reject, name='mail-reject'),
|
||||
url(r'^ajax/qualification-mail-save$', qualification_save, name='qualif-mail-save'),
|
||||
url(r'^ajax/mail/edit-note/$', edit_note, name='mail-edit-note'),
|
||||
url(r'^ajax/mail/note/(?P<pk>\w+)$', note, name='mail-note'),
|
||||
url(r'^ajax/count/mail/$', mail_count, name='mail-count'),
|
||||
url(r'^api/mail/response/$', mail_response, name='mail-api-response'),
|
||||
path('mail/viewer/', viewer, name='mail-viewer'),
|
||||
path('mail/feeder/', feeder, name='mail-feeder'),
|
||||
path('ajax/mail/reject', reject, name='mail-reject'),
|
||||
path('ajax/qualification-mail-save', qualification_save, name='qualif-mail-save'),
|
||||
path('ajax/mail/edit-note/', edit_note, name='mail-edit-note'),
|
||||
re_path(r'^ajax/mail/note/(?P<pk>\w+)$', note, name='mail-note'),
|
||||
path('ajax/count/mail/', mail_count, name='mail-count'),
|
||||
path('api/mail/response/', mail_response, name='mail-api-response'),
|
||||
]
|
||||
|
|
|
@ -32,7 +32,7 @@ class WelcoMaarchCourrier(MaarchCourrier):
|
|||
grc_response_status,
|
||||
batch_size=10,
|
||||
):
|
||||
super(WelcoMaarchCourrier, self).__init__(url, username, password)
|
||||
super().__init__(url, username, password)
|
||||
self.grc_status = grc_status
|
||||
self.grc_received_status = grc_received_status
|
||||
self.grc_send_status = grc_send_status
|
||||
|
@ -49,7 +49,7 @@ class WelcoMaarchCourrier(MaarchCourrier):
|
|||
)
|
||||
|
||||
def get_mail(self, mail_id):
|
||||
return self.get_courriers(clause="res_id=%s" % mail_id)[0]
|
||||
return self.get_courriers(clause='res_id=%s' % mail_id)[0]
|
||||
|
||||
def set_grc_received_status(self, mails):
|
||||
self.update_status(mails, self.grc_received_status)
|
||||
|
|
|
@ -18,27 +18,25 @@ import json
|
|||
import logging
|
||||
|
||||
from django import template
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib import messages
|
||||
from django.urls import reverse
|
||||
from django.template import RequestContext
|
||||
from django.db.transaction import atomic
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.template import RequestContext
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import TemplateView
|
||||
from django.db.transaction import atomic
|
||||
|
||||
from rest_framework import authentication, serializers, permissions, status
|
||||
from rest_framework import authentication, permissions, serializers, status
|
||||
from rest_framework.generics import GenericAPIView
|
||||
from rest_framework.response import Response
|
||||
|
||||
from welco.utils import response_for_json
|
||||
|
||||
from .models import Mail
|
||||
from .forms import MailQualificationForm
|
||||
from .utils import get_maarch, MaarchError
|
||||
|
||||
from .models import Mail
|
||||
from .utils import MaarchError, get_maarch
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -64,7 +62,7 @@ class Feeder(TemplateView):
|
|||
feeder = login_required(csrf_exempt(Feeder.as_view()))
|
||||
|
||||
|
||||
class Home(object):
|
||||
class Home:
|
||||
source_key = 'mail'
|
||||
display_filter = True
|
||||
allow_reject = True
|
||||
|
@ -112,7 +110,7 @@ class EditNote(TemplateView):
|
|||
template_name = 'welco/mail_edit_note.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EditNote, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['mail'] = Mail.objects.get(id=self.request.GET['mail'])
|
||||
return context
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.utils.timezone import utc
|
||||
from django.utils.timezone import now
|
||||
import datetime
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
from django.utils.timezone import now, utc
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -18,10 +18,10 @@ import logging
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.urls import reverse
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import now, timedelta
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from welco.qualif.models import Association
|
||||
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
# 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 django.urls import path, re_path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^ajax/phone/zone/$', views.zone, name='phone-zone'),
|
||||
url(r'^api/phone/call-event/$', views.call_event, name='phone-call-event'),
|
||||
url(r'^api/phone/active-call/(?P<pk>\w+)/$', views.active_call, name='phone-active-call'),
|
||||
url(r'^api/phone/current-calls/$', views.current_calls, name='phone-current-calls'),
|
||||
url(r'^api/phone/take-line/$', views.take_line, name='phone-take-line'),
|
||||
url(r'^api/phone/release-line/$', views.release_line, name='phone-release-line'),
|
||||
path('ajax/phone/zone/', views.zone, name='phone-zone'),
|
||||
path('api/phone/call-event/', views.call_event, name='phone-call-event'),
|
||||
re_path(r'^api/phone/active-call/(?P<pk>\w+)/$', views.active_call, name='phone-active-call'),
|
||||
path('api/phone/current-calls/', views.current_calls, name='phone-current-calls'),
|
||||
path('api/phone/take-line/', views.take_line, name='phone-take-line'),
|
||||
path('api/phone/release-line/', views.release_line, name='phone-release-line'),
|
||||
]
|
||||
|
|
|
@ -19,20 +19,19 @@ import logging
|
|||
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.template import RequestContext
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponseBadRequest, HttpResponse
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.template import RequestContext
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.timezone import now
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from .models import PhoneCall, PhoneLine
|
||||
|
||||
|
||||
class Home(object):
|
||||
class Home:
|
||||
source_key = 'phone'
|
||||
|
||||
def __init__(self, request, **kwargs):
|
||||
|
@ -60,7 +59,7 @@ class PhoneZone(TemplateView):
|
|||
username = username[0].split('@', 1)[0][:80] # remove realm
|
||||
if username:
|
||||
PhoneLine.take(callee=username, user=self.request.user)
|
||||
context = super(PhoneZone, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['source_type'] = ContentType.objects.get_for_model(PhoneCall)
|
||||
context['phonelines'] = PhoneLine.objects.filter(users__id=self.request.user.id)
|
||||
context['phonecalls'] = PhoneCall.get_current_calls(self.request.user)
|
||||
|
@ -85,22 +84,25 @@ def call_event(request):
|
|||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
try:
|
||||
payload = json.loads(force_text(request.body))
|
||||
payload = json.loads(force_str(request.body))
|
||||
assert isinstance(payload, dict), 'payload is not a JSON object'
|
||||
assert set(payload.keys()) <= set(
|
||||
['event', 'caller', 'callee', 'data']
|
||||
), 'payload keys must be "event", "caller", "callee" and optionnaly "data"'
|
||||
assert set(['event', 'caller', 'callee']) <= set(
|
||||
assert set(payload.keys()) <= {
|
||||
'event',
|
||||
'caller',
|
||||
'callee',
|
||||
'data',
|
||||
}, 'payload keys must be "event", "caller", "callee" and optionnaly "data"'
|
||||
assert {'event', 'caller', 'callee'} <= set(
|
||||
payload.keys()
|
||||
), 'payload keys must be "event", "caller", "callee" and optionnaly "data"'
|
||||
assert payload['event'] in ('start', 'stop'), 'event must be "start" or "stop"'
|
||||
assert isinstance(payload['caller'], six.string_types), 'caller must be a string'
|
||||
assert isinstance(payload['callee'], six.string_types), 'callee must be a string'
|
||||
assert isinstance(payload['caller'], str), 'caller must be a string'
|
||||
assert isinstance(payload['callee'], str), 'callee must be a string'
|
||||
if 'data' in payload:
|
||||
assert isinstance(payload['data'], dict), 'data must be a JSON object'
|
||||
except (TypeError, ValueError, AssertionError) as e:
|
||||
return HttpResponseBadRequest(
|
||||
json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json'
|
||||
json.dumps({'err': 1, 'msg': force_str(e)}), content_type='application/json'
|
||||
)
|
||||
# janitoring: stop active calls to the callee
|
||||
if settings.PHONE_ONE_CALL_PER_CALLEE:
|
||||
|
@ -200,15 +202,15 @@ def take_line(request):
|
|||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
try:
|
||||
payload = json.loads(force_text(request.body))
|
||||
payload = json.loads(force_str(request.body))
|
||||
assert isinstance(payload, dict), 'payload is not a JSON object'
|
||||
assert list(payload.keys()) == ['callee'], 'payload must have only one key: callee'
|
||||
except (TypeError, ValueError, AssertionError) as e:
|
||||
return HttpResponseBadRequest(
|
||||
json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json'
|
||||
json.dumps({'err': 1, 'msg': force_str(e)}), content_type='application/json'
|
||||
)
|
||||
PhoneLine.take(payload['callee'], request.user)
|
||||
logger.info(u'user %s took line %s', request.user, payload['callee'])
|
||||
logger.info('user %s took line %s', request.user, payload['callee'])
|
||||
return HttpResponse(json.dumps({'err': 0}), content_type='application/json')
|
||||
|
||||
|
||||
|
@ -221,13 +223,13 @@ def release_line(request):
|
|||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
try:
|
||||
payload = json.loads(force_text(request.body))
|
||||
payload = json.loads(force_str(request.body))
|
||||
assert isinstance(payload, dict), 'payload is not a JSON object'
|
||||
assert list(payload.keys()) == ['callee'], 'payload must have only one key: callee'
|
||||
except (TypeError, ValueError, AssertionError) as e:
|
||||
return HttpResponseBadRequest(
|
||||
json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json'
|
||||
json.dumps({'err': 1, 'msg': force_str(e)}), content_type='application/json'
|
||||
)
|
||||
PhoneLine.release(payload['callee'], request.user)
|
||||
logger.info(u'user %s released line %s', request.user, payload['callee'])
|
||||
logger.info('user %s released line %s', request.user, payload['callee'])
|
||||
return HttpResponse(json.dumps({'err': 0}), content_type='application/json')
|
||||
|
|
|
@ -14,71 +14,69 @@
|
|||
# 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 ckeditor import views as ckeditor_views
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include, url
|
||||
from django.conf.urls.static import static
|
||||
from django.contrib import admin
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
from django.urls import include, path, re_path
|
||||
from django.views.decorators.cache import never_cache
|
||||
|
||||
from ckeditor import views as ckeditor_views
|
||||
import welco.contacts.views
|
||||
import welco.kb.views
|
||||
import welco.views
|
||||
|
||||
from . import apps
|
||||
from .kb.views import kb_manager_required
|
||||
|
||||
import welco.views
|
||||
import welco.contacts.views
|
||||
import welco.kb.views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', welco.views.home, name='home'),
|
||||
url(r'^mail/$', welco.views.home_mail, name='home-mail'),
|
||||
url(r'^phone/$', welco.views.home_phone, name='home-phone'),
|
||||
url(r'^counter/$', welco.views.home_counter, name='home-counter'),
|
||||
url(r'^', include('welco.sources.phone.urls')),
|
||||
url(r'^', include('welco.sources.counter.urls')),
|
||||
url(r'^ajax/qualification$', welco.views.qualification, name='qualif-zone'),
|
||||
url(
|
||||
path('', welco.views.home, name='home'),
|
||||
path('mail/', welco.views.home_mail, name='home-mail'),
|
||||
path('phone/', welco.views.home_phone, name='home-phone'),
|
||||
path('counter/', welco.views.home_counter, name='home-counter'),
|
||||
re_path(r'^', include('welco.sources.phone.urls')),
|
||||
re_path(r'^', include('welco.sources.counter.urls')),
|
||||
path('ajax/qualification', welco.views.qualification, name='qualif-zone'),
|
||||
re_path(
|
||||
r'^ajax/remove-association/(?P<pk>\w+)$',
|
||||
welco.views.remove_association,
|
||||
name='ajax-remove-association',
|
||||
),
|
||||
url(r'^ajax/create-formdata/(?P<pk>\w+)$', welco.views.create_formdata, name='ajax-create-formdata'),
|
||||
url(r'^ajax/kb$', welco.kb.views.zone, name='kb-zone'),
|
||||
url(r'^kb/$', welco.kb.views.page_list, name='kb-home'),
|
||||
url(r'^kb/add/$', welco.kb.views.page_add, name='kb-page-add'),
|
||||
url(r'^kb/search/$', welco.kb.views.page_search, name='kb-page-search'),
|
||||
url(r'^kb/search/json/$', welco.kb.views.page_search_json, name='kb-page-search-json'),
|
||||
url(r'^kb/(?P<slug>[\w-]+)/$', welco.kb.views.page_detail, name='kb-page-view'),
|
||||
url(r'^ajax/kb/(?P<slug>[\w-]+)/$', welco.kb.views.page_detail_fragment, name='kb-page-fragment'),
|
||||
url(r'^kb/(?P<slug>[\w-]+)/edit$', welco.kb.views.page_edit, name='kb-page-edit'),
|
||||
url(r'^kb/(?P<slug>[\w-]+)/delete$', welco.kb.views.page_delete, name='kb-page-delete'),
|
||||
url(r'^ajax/contacts$', welco.contacts.views.zone, name='contacts-zone'),
|
||||
url(r'^contacts/search/json/$', welco.contacts.views.search_json, name='contacts-search-json'),
|
||||
url(
|
||||
re_path(r'^ajax/create-formdata/(?P<pk>\w+)$', welco.views.create_formdata, name='ajax-create-formdata'),
|
||||
path('ajax/kb', welco.kb.views.zone, name='kb-zone'),
|
||||
path('kb/', welco.kb.views.page_list, name='kb-home'),
|
||||
path('kb/add/', welco.kb.views.page_add, name='kb-page-add'),
|
||||
path('kb/search/', welco.kb.views.page_search, name='kb-page-search'),
|
||||
path('kb/search/json/', welco.kb.views.page_search_json, name='kb-page-search-json'),
|
||||
re_path(r'^kb/(?P<slug>[\w-]+)/$', welco.kb.views.page_detail, name='kb-page-view'),
|
||||
re_path(r'^ajax/kb/(?P<slug>[\w-]+)/$', welco.kb.views.page_detail_fragment, name='kb-page-fragment'),
|
||||
re_path(r'^kb/(?P<slug>[\w-]+)/edit$', welco.kb.views.page_edit, name='kb-page-edit'),
|
||||
re_path(r'^kb/(?P<slug>[\w-]+)/delete$', welco.kb.views.page_delete, name='kb-page-delete'),
|
||||
path('ajax/contacts', welco.contacts.views.zone, name='contacts-zone'),
|
||||
path('contacts/search/json/', welco.contacts.views.search_json, name='contacts-search-json'),
|
||||
re_path(
|
||||
r'^ajax/contacts/(?P<slug>[\w-]+)/$',
|
||||
welco.contacts.views.contact_detail_fragment,
|
||||
name='contact-page-fragment',
|
||||
),
|
||||
url(r'^contacts/add/$', welco.contacts.views.contact_add, name='contacts-add'),
|
||||
url(
|
||||
path('contacts/add/', welco.contacts.views.contact_add, name='contacts-add'),
|
||||
re_path(
|
||||
r'^ajax/summary/(?P<source_type>\w+)/(?P<source_pk>\w+)/$',
|
||||
welco.views.wcs_summary,
|
||||
name='wcs-summary',
|
||||
),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
url(r'^logout/$', welco.views.logout, name='auth_logout'),
|
||||
url(r'^login/$', welco.views.login, name='auth_login'),
|
||||
url(r'^menu.json$', welco.views.menu_json, name='menu_json'),
|
||||
url(r'^ckeditor/upload/', kb_manager_required(ckeditor_views.upload), name='ckeditor_upload'),
|
||||
url(
|
||||
re_path(r'^admin/', admin.site.urls),
|
||||
path('logout/', welco.views.logout, name='auth_logout'),
|
||||
path('login/', welco.views.login, name='auth_login'),
|
||||
re_path(r'^menu.json$', welco.views.menu_json, name='menu_json'),
|
||||
re_path(r'^ckeditor/upload/', kb_manager_required(ckeditor_views.upload), name='ckeditor_upload'),
|
||||
re_path(
|
||||
r'^ckeditor/browse/', never_cache(kb_manager_required(ckeditor_views.browse)), name='ckeditor_browse'
|
||||
),
|
||||
]
|
||||
|
||||
if 'mellon' in settings.INSTALLED_APPS:
|
||||
urlpatterns.append(url(r'^accounts/mellon/', include('mellon.urls')))
|
||||
urlpatterns.append(re_path(r'^accounts/mellon/', include('mellon.urls')))
|
||||
|
||||
# static and media files
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
|
|
@ -16,25 +16,25 @@
|
|||
|
||||
import base64
|
||||
import datetime
|
||||
import hmac
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import requests
|
||||
import urllib.parse
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.utils.encoding import smart_bytes
|
||||
from django.utils.http import urlencode, quote
|
||||
from django.utils.six.moves.urllib import parse as urlparse
|
||||
from django.utils.http import quote, urlencode
|
||||
|
||||
|
||||
def sign_url(url, key, algo='sha256', timestamp=None, nonce=None):
|
||||
parsed = urlparse.urlparse(url)
|
||||
parsed = urllib.parse.urlparse(url)
|
||||
new_query = sign_query(parsed.query, key, algo, timestamp, nonce)
|
||||
return urlparse.urlunparse(parsed[:4] + (new_query,) + parsed[5:])
|
||||
return urllib.parse.urlunparse(parsed[:4] + (new_query,) + parsed[5:])
|
||||
|
||||
|
||||
def sign_query(query, key, algo='sha256', timestamp=None, nonce=None):
|
||||
|
|
|
@ -16,20 +16,20 @@
|
|||
|
||||
import json
|
||||
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout as auth_logout
|
||||
from django.contrib.auth import views as auth_views
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.urls import reverse
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import resolve_url
|
||||
from django import template
|
||||
from django.template import RequestContext
|
||||
from django.utils.encoding import force_text
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.http import quote
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
|
@ -38,13 +38,14 @@ if 'mellon' in settings.INSTALLED_APPS:
|
|||
else:
|
||||
get_idps = lambda: []
|
||||
|
||||
from .sources.mail.views import Home as MailHome
|
||||
from .sources.phone.views import Home as PhoneHome
|
||||
from .sources.counter.views import Home as CounterHome
|
||||
from .qualif.models import Association
|
||||
from .kb.views import HomeZone as KbHomeZone, check_user_perms as check_kb_user_perms
|
||||
from .contacts.views import HomeZone as ContactsHomeZone
|
||||
from .forms import QualificationForm
|
||||
from .kb.views import HomeZone as KbHomeZone
|
||||
from .kb.views import check_user_perms as check_kb_user_perms
|
||||
from .qualif.models import Association
|
||||
from .sources.counter.views import Home as CounterHome
|
||||
from .sources.mail.views import Home as MailHome
|
||||
from .sources.phone.views import Home as PhoneHome
|
||||
|
||||
|
||||
class LoginView(auth_views.LoginView):
|
||||
|
@ -59,7 +60,7 @@ class LoginView(auth_views.LoginView):
|
|||
except KeyError:
|
||||
return HttpResponseBadRequest('invalid value for "next" parameter')
|
||||
return HttpResponseRedirect(resolve_url('mellon_login') + '?next=' + quoted_next_url)
|
||||
return super(LoginView, self).dispatch(request, *args, **kwargs)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
login = LoginView.as_view()
|
||||
|
@ -80,7 +81,7 @@ class Qualification(TemplateView):
|
|||
template_name = 'welco/qualification_no_validation.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(Qualification, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['form'] = QualificationForm(self.request.user)
|
||||
context['source_type'] = self.request.GET['source_type']
|
||||
source_type = ContentType.objects.get(id=self.request.GET['source_type'])
|
||||
|
@ -112,21 +113,21 @@ class ChannelHome(TemplateView):
|
|||
source_klass = MailHome
|
||||
|
||||
def check_user_ok(self):
|
||||
user_groups = set([x.name for x in self.request.user.groups.all()])
|
||||
user_groups = {x.name for x in self.request.user.groups.all()}
|
||||
channel_groups = set(settings.CHANNEL_ROLES[self.source_klass.source_key])
|
||||
return user_groups.intersection(channel_groups)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
if not self.check_user_ok():
|
||||
raise PermissionDenied()
|
||||
context = super(ChannelHome, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['panels'] = [{'key': x, 'zone_url': x + '-zone'} for x in settings.SCREEN_PANELS]
|
||||
context['source'] = self.source_klass(self.request, **kwargs)
|
||||
context['kb'] = KbHomeZone(self.request)
|
||||
context['contacts'] = ContactsHomeZone(self.request)
|
||||
context['channels'] = []
|
||||
|
||||
user_groups = set([x.name for x in self.request.user.groups.all()])
|
||||
user_groups = {x.name for x in self.request.user.groups.all()}
|
||||
for channel in settings.CHANNEL_ROLES:
|
||||
channel_groups = set(settings.CHANNEL_ROLES[channel])
|
||||
if user_groups.intersection(channel_groups):
|
||||
|
@ -136,7 +137,7 @@ class ChannelHome(TemplateView):
|
|||
|
||||
@login_required
|
||||
def home(request):
|
||||
user_groups = set([x.name for x in request.user.groups.all()])
|
||||
user_groups = {x.name for x in request.user.groups.all()}
|
||||
for channel in settings.CHANNEL_ROLES:
|
||||
channel_groups = set(settings.CHANNEL_ROLES[channel])
|
||||
if user_groups.intersection(channel_groups):
|
||||
|
@ -209,7 +210,7 @@ def create_formdata(request, *args, **kwargs):
|
|||
@login_required
|
||||
def menu_json(request):
|
||||
response = HttpResponse(content_type='application/json')
|
||||
user_groups = set([x.name for x in request.user.groups.all()])
|
||||
user_groups = {x.name for x in request.user.groups.all()}
|
||||
menu = []
|
||||
labels = {
|
||||
'mail': _('Mails'),
|
||||
|
@ -221,7 +222,7 @@ def menu_json(request):
|
|||
if user_groups.intersection(channel_groups):
|
||||
menu.append(
|
||||
{
|
||||
'label': force_text(labels.get(channel)),
|
||||
'label': force_str(labels.get(channel)),
|
||||
'slug': channel,
|
||||
'url': request.build_absolute_uri(reverse('home-%s' % channel)),
|
||||
}
|
||||
|
@ -229,7 +230,7 @@ def menu_json(request):
|
|||
if check_kb_user_perms(request.user, access=True):
|
||||
menu.append(
|
||||
{
|
||||
'label': force_text(_('Knowledge Base')),
|
||||
'label': force_str(_('Knowledge Base')),
|
||||
'slug': 'book',
|
||||
'url': request.build_absolute_uri(reverse('kb-home')),
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
|||
|
||||
import os
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "welco.settings")
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'welco.settings')
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
|
|
Loading…
Reference in New Issue