diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000000000000000000000000000000000000..9a8b02b988c941e3be27da4f6599b8615df49f77 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,7 @@ +[run] +omit= + setup.py + ucamlookup/tests/* + ucamlookup/wsgi.py + .tox/* + ucamlookup/migrations/* diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000000000000000000000000000000000000..467858906d36240c19f79a56e08c3ee63523654f --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length=120 +exclude = venv,.tox,ibisclient,build/* diff --git a/.gitignore b/.gitignore index b23187f78f5421f133637a37b9624026618256a6..538ef73e5af708403be0f1e6c5e620d5d2aace22 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ dist .DS_Store django_ucamlookup.egg-info -MANIFEST \ No newline at end of file +MANIFEST +.tox +build +.coverage diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0fb2c2ad1f3155d1e1e61fa02baf5aed42f55ba2..0000000000000000000000000000000000000000 --- a/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: python -python: - - 2.7 - - 3.4 - - 3.5 -env: - - DJANGO="django>=1.8,<1.9" - - DJANGO="django>=1.9,<1.10" - - DJANGO="django>=1.10,<1.11" -install: - - pip install $DJANGO - - pip install requests - - python setup.py -q install -script: python runtests.py -notifications: - email: false diff --git a/README.md b/README.md index a1e1212050ed94e33578d86ddccf1224243a7b23..442d0ad4f0e955b015a17edb44e28f1d726f3760 100644 --- a/README.md +++ b/README.md @@ -149,4 +149,15 @@ class MyModelAdmin(ModelAdmin): return get_institution_name_by_id(obj.institution_id, self.all_institutions) institution.admin_order_field = 'institution_id' -``` \ No newline at end of file +``` + +# Developing + +## Run tests + +Tox is configured to run on a container with a matrix execution of different versions of python and django combined. +It will also show the coverage and any possible PEP8 violations. + +```shell +$ docker-compose up +``` diff --git a/README.rst b/README.rst index 306848a48980608fe72a3095ba31462ff1f3c1fd..14985f807481a25e942a5107a6297903d9124b16 100644 --- a/README.rst +++ b/README.rst @@ -187,3 +187,16 @@ the name instead of the code in the admin interface institution.admin_order_field = 'institution_id' + +Developing +========== + +Run tests +--------- + +Tox is configured to run on a container with a matrix execution of different versions of python and django combined. +It will also show the coverage and any possible PEP8 violations. + +.. code:: shell + + $ docker-compose up diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index d6be17a2e5da0a7bbb59bd1994efe312957e4526..0000000000000000000000000000000000000000 --- a/debian/changelog +++ /dev/null @@ -1,86 +0,0 @@ -django-ucamlookup (1.9.1) jessie; urgency=medium - - * Retarget build at jessie. - - -- Jon Warbrick <jw35@cam.ac.uk> Thu, 15 Sep 2016 14:53:33 +0100 - -django-ucamlookup (1.9) unstable; urgency=medium - - * Fix XSS vulnerability on template macros - - -- Jon Warbrick <jw35@cam.ac.uk> Thu, 15 Sep 2016 11:11:08 +0100 - -django-ucamlookup (1.7.1) unstable; urgency=low - - * Import utilities to the root package - - -- Abraham Martin <amc203@cam.ac.uk> Mon, 13 Jun 2016 9:11:02 +0100 - -django-ucamlookup (1.7) unstable; urgency=low - - * Added Python 3 support - - -- Abraham Martin <amc203@cam.ac.uk> Mon, 6 Jun 2016 11:15:12 +0100 - -django-ucamlookup (1.6.1) unstable; urgency=high - - * Return empty LookupGroup list if IbisException - - -- Abraham Martin <amc203@cam.ac.uk> Fri, 9 Oct 2015 11:58:39 +0100 - -django-ucamlookup (1.6) unstable; urgency=high - - * Dropped support for django 1.6 (no longer supported by django project) - * Added the option to retrieve the LookupGroup object using get_user_lookupgroups - - -- Abraham Martin <amc203@cam.ac.uk> Fri, 9 Oct 2015 10:37:11 +0100 - -django-ucamlookup (1.5) unstable; urgency=high - - * Updated ibisclient to 1.2.5 - - -- Abraham Martin <amc203@cam.ac.uk> Wed, 25 Jun 2015 10:58:20 +0100 - -django-ucamlookup (1.4) unstable; urgency=high - - * Unified debian and pypi versions - - -- Abraham Martin <amc203@cam.ac.uk> Wed, 14 May 2015 16:18:21 +0100 - -django-ucamlookup (1.2.1) unstable; urgency=high - - * Limitation of the maximum characters the User.last_name (30) and - Group.name (80) can have - - -- Abraham Martin <amc203@cam.ac.uk> Wed, 13 May 2015 16:37:01 +0100 - -django-ucamlookup (1.2) unstable; urgency=low - - * Updated ibisclient to 1.2.3 - - -- Abraham Martin <amc203@cam.ac.uk> Fri, 1 May 2015 09:42:24 +0100 - -django-ucamlookup (1.1.2) unstable; urgency=low - - * Remove University Computing Service from test_get_institutions_with_user - - -- Matthew Vernon <mcv21@cam.ac.uk> Fri, 06 Mar 2015 17:32:10 +0000 - -django-ucamlookup (1.1.1) unstable; urgency=low - - * Correct package name in changelog - * Add myself to Uploaders - - -- Matthew Vernon <mcv21@cam.ac.uk> Fri, 06 Mar 2015 17:15:35 +0000 - -django-ucamlookup (1.1) unstable; urgency=low - - * New upstream release (updated to 1.1) - - -- Abraham Martin <amc203@cam.ac.uk> Wed, 19 Sep 2014 13:54:53 +0100 - -django-ucamlookup (1.0) unstable; urgency=low - - * Initial debianisation - - -- Abraham Martin <amc203@cam.ac.uk> Tue, 19 Aug 2014 11:30:39 +0100 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7f8f011eb73d6043d2e6db9d2c101195ae2801f2..0000000000000000000000000000000000000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/debian/control b/debian/control deleted file mode 100644 index 338f44ac05d4cdcf10ce46e604485501c259cf57..0000000000000000000000000000000000000000 --- a/debian/control +++ /dev/null @@ -1,16 +0,0 @@ -Source: django-ucamlookup -Maintainer: UIS Information Systems Group, University of Cambridge <information-systems@ucs.cam.ac.uk> -Uploaders: Abraham Martin <amc203@cam.ac.uk>, - Matthew Vernon <mcv21@cam.ac.uk> -Section: python -Priority: optional -Build-Depends: python-setuptools, python-all (>= 2.6.6-3), debhelper (>=9), - python-django (>=1.7), python-markdown, dh-python -Standards-Version: 3.9.4 - -Package: python-django-ucamlookup -Architecture: all -Depends: python-django (>=1.7), python-requests, python-openssl, ${misc:Depends}, ${python:Depends} -Description: University of Cambridge Web Authentication module for Django - This package provides a django authentication back-end to the - University of Cambridge Web Authentication system. diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 622a9ac0aff0ec8b30b1a8849d344645dc3f6279..0000000000000000000000000000000000000000 --- a/debian/copyright +++ /dev/null @@ -1,30 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: django-ucamlookup -Upstream-Contact: Information Systems, University Information Service, University of Cambridge - <information-systems@ucs.cam.ac.uk> -Source: https://github.com/uisautomation/django-ucamlookup.git - -Files: * -Copyright: Copyright (c) 2015, University of Cambridge and individual contributors. -License: MIT - Copyright (c) 2015, University of Cambridge and individual contributors. - . - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - . - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - . - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. diff --git a/debian/docs b/debian/docs deleted file mode 100644 index daa30a3f752706bce3bc36b34a7aab39ee5484d4..0000000000000000000000000000000000000000 --- a/debian/docs +++ /dev/null @@ -1 +0,0 @@ -README.html diff --git a/debian/rules b/debian/rules deleted file mode 100755 index b2bbced08b77d08b9249644f1b200b61f6674032..0000000000000000000000000000000000000000 --- a/debian/rules +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/make -f - -export PYBUILD_NAME=django-ucamlookup -export PYBUILD_DISABLE=test - -%: - dh $@ --with python2 --buildsystem=pybuild - -override_dh_auto_build: - dh_auto_build - sed -e '1d' < README.md | markdown_py > README.html - -override_dh_auto_test: - python runtests.py - -override_dh_auto_clean: - dh_auto_clean - rm -f README.html diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..ad1f7907bf4b0681274788341cafd06202ad7295 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +# docker-compose file for local development and testing with container image. +# +# Extends compose/base.yml so launch services via: +# +# docker-compose -f compose/base.yml -f compose/tox.yml run --rm tox <...> +version: '3.2' +services: + tox: + image: themattrix/tox-base + entrypoint: tox + environment: + - TOXINI_WORK_DIR=/tmp/tox-data/work + - TOXINI_ARTEFACT_DIR=/tmp/tox-data/artefacts + - TOXINI_COVERAGE_FILE=/tmp/tox-coverage + volumes: + - tox-data:/tmp/tox-data + - ./:/app:ro + +volumes: + # A persistent volume for tox to store its stuff. This allows caching of + # virtualenvs between runs. + tox-data: diff --git a/requirements.txt b/requirements.txt index 68d357cf83faf9e80e9c4ce4d7ab925ee9e36958..205e224ff82115d30a27c04876b3ac6861e66ec8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -django \ No newline at end of file +django>=1.11 +tox diff --git a/requirements_jenkins.txt b/requirements_jenkins.txt deleted file mode 100644 index cb4de6702076a7401c67636fd22274b4d9c8012c..0000000000000000000000000000000000000000 --- a/requirements_jenkins.txt +++ /dev/null @@ -1,7 +0,0 @@ -django>=1.11 -django-jenkins -coverage -pylint -pep8>=1.3 -pyflakes -pylint-django diff --git a/runtests.py b/runtests.py index 7a40ad8ae6d70f7954cd776cab250eb682db9797..d414f93aeb199b765271f90ed6e510489c375963 100755 --- a/runtests.py +++ b/runtests.py @@ -31,6 +31,14 @@ settings.configure( 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), + MIDDLEWARE=( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + ), TEMPLATES=[ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', diff --git a/runtestsjenkins.py b/runtestsjenkins.py deleted file mode 100755 index ae72df575eb5f3e735101580b8d957eaf910928b..0000000000000000000000000000000000000000 --- a/runtestsjenkins.py +++ /dev/null @@ -1,66 +0,0 @@ -import os -import sys -from django.core.management import execute_from_command_line -from django.conf import settings - -settings.configure( - DEBUG=False, - DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'test.db', }}, - TIME_ZONE='Europe/London', - USE_TZ=True, - ROOT_URLCONF='ucamlookup.urls', - PROJECT_APPS=( - 'ucamlookup', - ), - INSTALLED_APPS=( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'ucamlookup', - 'django_jenkins', - ), - MIDDLEWARE_CLASSES=( - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - ), - TEMPLATES=[ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - # insert your TEMPLATE_DIRS here - ], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - # Insert your TEMPLATE_CONTEXT_PROCESSORS here or use this - # list if you haven't customized them: - 'django.contrib.auth.context_processors.auth', - 'django.template.context_processors.debug', - 'django.template.context_processors.i18n', - 'django.template.context_processors.media', - 'django.template.context_processors.static', - 'django.template.context_processors.tz', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, - ], - JENKINS_TASKS=( - 'django_jenkins.tasks.run_pylint', - # 'django_jenkins.tasks.run_csslint', - 'django_jenkins.tasks.run_pep8', - 'django_jenkins.tasks.run_pyflakes', - 'django_jenkins.tasks.run_sloccount', - ), - PEP8_RCFILE=os.path.join(os.path.dirname(os.path.dirname(__file__)), 'jenkins/pep8'), - PYLINT_RCFILE=os.path.join(os.path.dirname(os.path.dirname(__file__)), 'jenkins/pylint'), -) - -execute_from_command_line(sys.argv) diff --git a/setup.py b/setup.py index e77982496e01cf2182a78614fac0d0f6acf347bc..7f700502cd5758674ad0799c0d14c74e6f858acf 100755 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( author_email='devops@uis.cam.ac.uk', packages=find_packages(), include_package_data=True, - install_requires=['django>=1.8'], + install_requires=['django>=1.11'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000000000000000000000000000000000000..e443d5f914ab17cb82a1f578a5fbec0c47c81e68 --- /dev/null +++ b/tox.ini @@ -0,0 +1,73 @@ +# Tox runner configuration +# +# The following optional environment variables can change behaviour. See the +# comments where they are used for more information. +# +# - TOXINI_ARTEFACT_DIR +# - TOXINI_FLAKE8_VERSION +# - TOXINI_WORK_DIR +# +[tox] +# Envs which should be run by default. This will execute a matrix of tests +envlist = + py{27,34,35,36}-django111 + py{34,35,36, 37}-django20 + py{35,36, 37}-django21 + coverage + flake8 +# Allow overriding toxworkdir via environment variable +toxworkdir={env:TOXINI_WORK_DIR:{toxinidir}/.tox} +# Do not attempt to create .egg-info directories in the application root as it +# is mounted as a read-only volume. +skipsdist=true + +# The "_vars" section is ignored by tox but we place some useful shared +# variables in it to avoid needless repetition. +[_vars] +# Where to write build artefacts. We default to the "build" directory in the +# tox.ini file's directory. Override with the TOXINI_ARTEFACT_DIR environment +# variable. +build_root={env:TOXINI_ARTEFACT_DIR:{toxinidir}/build} + +[testenv] +setenv= +# Override the coverage dtaa file location since the application root is +# mounted read-only. + COVERAGE_FILE={env:TOXINI_COVERAGE_FILE:{toxinidir}/.coverage} +# Additional dependencies +deps= + coverage + django111: Django>=1.11,<2.0 + django20: Django>=2.0,<2.1 + django21: Django>=2.1,<2.2 +# Specify the default environment. +commands= + coverage run --source={toxinidir} ./runtests.py + +# Check for PEP8 violations +[testenv:flake8] +basepython=python3 +deps= + -rrequirements.txt +# We specify a specific version of flake8 to avoid introducing "false" +# regressions when new checks are introduced. The version of flake8 used may +# be overridden via the TOXINI_FLAKE8_VERSION environment variable. + flake8=={env:TOXINI_FLAKE8_VERSION:3.6.0} +commands= + flake8 --version + flake8 . + +# Check for PEP8 violations +[testenv:coverage] +basepython=python3 +deps= + coverage + django +# Specify the default environment. Note that tox will *always* use the testsuite +# settings unless overridden by TOX_DJANGO_SETTINGS_MODULE. Just setting +# DJANGO_SETTINGS_MODULE will not override it. +commands= + coverage run --source={toxinidir} ./runtests.py + coverage html --directory {[_vars]build_root}/htmlcov/ + coverage report + coverage xml -o {env:COVERAGE_XML_FILE:{[_vars]build_root}/coverage.xml} diff --git a/ucamlookup/__init__.py b/ucamlookup/__init__.py index 037829cbac62a7890520967354fe97f9e80da772..91fac1e9efc1f1b9f8c195e853adaf970cffd3f3 100644 --- a/ucamlookup/__init__.py +++ b/ucamlookup/__init__.py @@ -1,4 +1,4 @@ -from ucamlookup.utils import * +from ucamlookup.utils import * # noqa: F403,F401 default_app_config = 'ucamlookup.apps.UCamLookupConfig' diff --git a/ucamlookup/admin.py b/ucamlookup/admin.py index 4437e581ebad92116f5c73ec7dff2debef38a1eb..f4acb805787ec986ddcb9f36f4868f8efa2bc490 100644 --- a/ucamlookup/admin.py +++ b/ucamlookup/admin.py @@ -6,7 +6,7 @@ from django import forms from ucamlookup.models import LookupGroup -class UserCreationForm(forms.ModelForm): +class UserCreationForm(forms.ModelForm): # noqa: F811 """ A form that creates a user, with no privileges, from the given username and password. diff --git a/ucamlookup/apps.py b/ucamlookup/apps.py index 79c0ac6461a0a57d43632872607b15ef8da47f6b..6553c9c1f30b5e12e0bddd340c1e4720059046d6 100644 --- a/ucamlookup/apps.py +++ b/ucamlookup/apps.py @@ -7,4 +7,4 @@ class UCamLookupConfig(AppConfig): def ready(self): super(UCamLookupConfig, self).ready() - import ucamlookup.signals + import ucamlookup.signals # noqa: F401 diff --git a/ucamlookup/tests.py b/ucamlookup/tests.py index a9666f2b48ec4a7e122bb3878e3d71df99746fc0..5a3b8f012957d50e7ac3c7e6274db155dfd7ab3b 100644 --- a/ucamlookup/tests.py +++ b/ucamlookup/tests.py @@ -2,7 +2,10 @@ import json import sys from django.contrib.auth.models import User from django.core.exceptions import ValidationError -from django.core.urlresolvers import reverse +try: + from django.core.urlresolvers import reverse +except Exception: + from django.urls import reverse from django.test import TestCase from ucamlookup.models import LookupGroup from ucamlookup.utils import user_in_groups, get_users_from_query, return_visibleName_by_crsid, get_groups_from_query, \ @@ -18,7 +21,7 @@ class UcamLookupTests(TestCase): user1 = User.objects.create_user(username="amc203") user2 = User.objects.get(username="amc203") self.assertEqual(user1.id, user2.id) - self.assertEqual(user2.last_name, "Dr Abraham Martin Campillo") + self.assertEqual(user2.last_name, "Dr Abraham Martin") with self.assertRaises(LookupGroup.DoesNotExist): LookupGroup.objects.get(lookup_id="101888") @@ -39,16 +42,16 @@ class UcamLookupTests(TestCase): results = get_users_from_query("amc203") self.assertEqual(len(results), 1) self.assertEqual(results[0]['crsid'], "amc203") - self.assertEqual(results[0]['visibleName'], "Dr Abraham Martin Campillo") + self.assertEqual(results[0]['visibleName'], "Dr Abraham Martin") - results = get_users_from_query("Abraham Martin Campillo") + results = get_users_from_query("Abraham Martin") self.assertEqual(len(results), 1) self.assertEqual(results[0]['crsid'], "amc203") - self.assertEqual(results[0]['visibleName'], "Dr Abraham Martin Campillo") + self.assertEqual(results[0]['visibleName'], "Dr Abraham Martin") def test_return_visibleName_by_crsid(self): result = return_visibleName_by_crsid("amc203") - self.assertEqual(result, "Dr Abraham Martin Campillo") + self.assertEqual(result, "Dr Abraham Martin") result = return_visibleName_by_crsid("amc20311") self.assertEqual(result, '') @@ -107,7 +110,7 @@ class UcamLookupTests(TestCase): User.objects.create_user(username="amc203", password="test") self.assertTrue(self.client.login(username='amc203', password="test")) response = self.client.get(reverse('ucamlookup_find_people'), {'query': 'amc203', 'searchId_u': '1'}) - if sys.version_info >= (3,0): + if sys.version_info >= (3, 0): jsonresponse = json.loads(response.content.decode('utf-8')) else: jsonresponse = json.loads(response.content) @@ -115,7 +118,7 @@ class UcamLookupTests(TestCase): self.assertIn('searchId_u', jsonresponse) self.assertEqual(jsonresponse['searchId_u'], "1") self.assertEqual(len(jsonresponse['persons']), 1) - self.assertEqual(jsonresponse['persons'][0]['visibleName'], "Dr Abraham Martin Campillo") + self.assertEqual(jsonresponse['persons'][0]['visibleName'], "Dr Abraham Martin") self.assertEqual(jsonresponse['persons'][0]['crsid'], "amc203") def test_findgroups_view(self): @@ -123,7 +126,7 @@ class UcamLookupTests(TestCase): self.assertTrue(self.client.login(username='amc203', password="test")) response = self.client.get(reverse('ucamlookup_find_groups'), {'query': 'Information Systems', 'searchId_g': '1'}) - if sys.version_info >= (3,0): + if sys.version_info >= (3, 0): jsonresponse = json.loads(response.content.decode('utf-8')) else: jsonresponse = json.loads(response.content) diff --git a/ucamlookup/utils.py b/ucamlookup/utils.py index 80eae3ddd2b1823aa3b48237b83a88b1e54490a5..c0a6552bfbf85b301611086e2bbf72044b401ef8 100644 --- a/ucamlookup/utils.py +++ b/ucamlookup/utils.py @@ -1,6 +1,6 @@ import re from django.core.exceptions import ValidationError -from ucamlookup.ibisclient import * +from ucamlookup.ibisclient import createConnection, PersonMethods, GroupMethods, IbisException, InstitutionMethods conn = createConnection() diff --git a/ucamlookup/views.py b/ucamlookup/views.py index 761826c72aa192d06cb74796221feb3d7e6cae88..70f2085684731827a5544fd42be0b36f96be1855 100644 --- a/ucamlookup/views.py +++ b/ucamlookup/views.py @@ -10,6 +10,7 @@ def find_people(request): return HttpResponse(json.dumps({'searchId_u': request.GET.get('searchId_u'), 'persons': persons}), content_type='application/json') + @login_required def find_groups(request): groups = get_groups_from_query(request.GET.get('query'))