Add new version email and info box then new version is available
This commit is contained in:
parent
6eea76d984
commit
b6cffcf482
15 changed files with 301 additions and 3 deletions
10
README.rst
10
README.rst
|
@ -219,6 +219,16 @@ Federation settings
|
||||||
``_remember_provider``.
|
``_remember_provider``.
|
||||||
|
|
||||||
|
|
||||||
|
New version warnings settings
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
* ``CAS_NEW_VERSION_HTML_WARNING``: A boolean for diplaying a warning on html pages then a new
|
||||||
|
version of the application is avaible. Once closed by a user, it is not displayed to this user
|
||||||
|
until the next new version. The default is ``True``.
|
||||||
|
* ``CAS_NEW_VERSION_EMAIL_WARNING``: A bolean sot sending a email to ``settings.ADMINS`` when a new
|
||||||
|
version is available. The default is ``True``.
|
||||||
|
|
||||||
|
|
||||||
Tickets validity settings
|
Tickets validity settings
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|
|
@ -9,5 +9,9 @@
|
||||||
#
|
#
|
||||||
# (c) 2015-2016 Valentin Samir
|
# (c) 2015-2016 Valentin Samir
|
||||||
"""A django CAS server application"""
|
"""A django CAS server application"""
|
||||||
|
|
||||||
|
#: version of the application
|
||||||
|
VERSION = '0.6.1'
|
||||||
|
|
||||||
#: path the the application configuration class
|
#: path the the application configuration class
|
||||||
default_app_config = 'cas_server.apps.CasAppConfig'
|
default_app_config = 'cas_server.apps.CasAppConfig'
|
||||||
|
|
|
@ -140,6 +140,15 @@ CAS_FEDERATE = False
|
||||||
#: Time after witch the cookie use for “remember my identity provider” expire (one week).
|
#: Time after witch the cookie use for “remember my identity provider” expire (one week).
|
||||||
CAS_FEDERATE_REMEMBER_TIMEOUT = 604800
|
CAS_FEDERATE_REMEMBER_TIMEOUT = 604800
|
||||||
|
|
||||||
|
#: A :class:`bool` for diplaying a warning on html pages then a new version of the application
|
||||||
|
#: is avaible. Once closed by a user, it is not displayed to this user until the next new version.
|
||||||
|
CAS_NEW_VERSION_HTML_WARNING = True
|
||||||
|
#: A :class:`bool` for sending emails to ``settings.ADMINS`` when a new version is available.
|
||||||
|
CAS_NEW_VERSION_EMAIL_WARNING = True
|
||||||
|
#: URL to the pypi json of the application. Used to retreive the version number of the last version.
|
||||||
|
#: You should not change it.
|
||||||
|
CAS_NEW_VERSION_JSON_URL = "https://pypi.python.org/pypi/django-cas-server/json"
|
||||||
|
|
||||||
GLOBALS = globals().copy()
|
GLOBALS = globals().copy()
|
||||||
for name, default_value in GLOBALS.items():
|
for name, default_value in GLOBALS.items():
|
||||||
# get the current setting value, falling back to default_value
|
# get the current setting value, falling back to default_value
|
||||||
|
|
|
@ -23,3 +23,4 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
models.User.clean_deleted_sessions()
|
models.User.clean_deleted_sessions()
|
||||||
|
models.NewVersionWarning.send_mails()
|
||||||
|
|
22
cas_server/migrations/0008_newversionwarning.py
Normal file
22
cas_server/migrations/0008_newversionwarning.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.7 on 2016-07-27 21:59
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cas_server', '0007_auto_20160723_2252'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='NewVersionWarning',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('version', models.CharField(max_length=255)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
|
@ -18,15 +18,19 @@ from django.contrib import messages
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import smtplib
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from requests_futures.sessions import FuturesSession
|
from requests_futures.sessions import FuturesSession
|
||||||
|
|
||||||
import cas_server.utils as utils
|
import cas_server.utils as utils
|
||||||
|
from . import VERSION
|
||||||
|
|
||||||
#: logger facility
|
#: logger facility
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -1003,3 +1007,60 @@ class Proxy(models.Model):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.url
|
return self.url
|
||||||
|
|
||||||
|
|
||||||
|
class NewVersionWarning(models.Model):
|
||||||
|
"""
|
||||||
|
Bases: :class:`django.db.models.Model`
|
||||||
|
|
||||||
|
The last new version available version sent
|
||||||
|
"""
|
||||||
|
version = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def send_mails(cls):
|
||||||
|
"""
|
||||||
|
For each new django-cas-server version, if the current instance is not up to date
|
||||||
|
send one mail to ``settings.ADMINS``.
|
||||||
|
"""
|
||||||
|
if settings.CAS_NEW_VERSION_EMAIL_WARNING and settings.ADMINS:
|
||||||
|
try:
|
||||||
|
obj = cls.objects.get()
|
||||||
|
except cls.DoesNotExist:
|
||||||
|
obj = NewVersionWarning.objects.create(version=VERSION)
|
||||||
|
LAST_VERSION = utils.last_version()
|
||||||
|
if LAST_VERSION is not None and LAST_VERSION != obj.version:
|
||||||
|
if utils.decode_version(VERSION) < utils.decode_version(LAST_VERSION):
|
||||||
|
try:
|
||||||
|
send_mail(
|
||||||
|
(
|
||||||
|
'%sA new version of django-cas-server is available'
|
||||||
|
) % settings.EMAIL_SUBJECT_PREFIX,
|
||||||
|
u'''
|
||||||
|
A new version of the django-cas-server is available.
|
||||||
|
|
||||||
|
Your version: %s
|
||||||
|
New version: %s
|
||||||
|
|
||||||
|
Upgrade using:
|
||||||
|
* pip install -U django-cas-server
|
||||||
|
* fetching the last release on
|
||||||
|
https://github.com/nitmir/django-cas-server/ or on
|
||||||
|
https://pypi.python.org/pypi/django-cas-server
|
||||||
|
|
||||||
|
After upgrade, do not forget to run:
|
||||||
|
* ./manage.py migrate
|
||||||
|
* ./manage.py collectstatic
|
||||||
|
and to reload your wsgi server (apache2, uwsgi, gunicord, etc…)
|
||||||
|
|
||||||
|
--\u0020
|
||||||
|
django-cas-server
|
||||||
|
'''.strip() % (VERSION, LAST_VERSION),
|
||||||
|
settings.SERVER_EMAIL,
|
||||||
|
["%s <%s>" % admin for admin in settings.ADMINS],
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
obj.version = LAST_VERSION
|
||||||
|
obj.save()
|
||||||
|
except smtplib.SMTPException as error: # pragma: no cover (should not happen)
|
||||||
|
logger.error("Unable to send new version mail: %s" % error)
|
||||||
|
|
25
cas_server/static/cas_server/alert-version.js
Normal file
25
cas_server/static/cas_server/alert-version.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
function alert_version(last_version){
|
||||||
|
jQuery(function( $ ){
|
||||||
|
$('#alert-version').click(function( e ){
|
||||||
|
e.preventDefault();
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime()+(10*365*24*60*60*1000));
|
||||||
|
var expires = "; expires="+date.toGMTString();
|
||||||
|
document.cookie = "cas-alert-version=" + last_version + expires + "; path=/";
|
||||||
|
});
|
||||||
|
|
||||||
|
var nameEQ="cas-alert-version="
|
||||||
|
var ca = document.cookie.split(';');
|
||||||
|
var value;
|
||||||
|
for(var i=0;i < ca.length;i++) {
|
||||||
|
var c = ca[i];
|
||||||
|
while (c.charAt(0)==' ')
|
||||||
|
c = c.substring(1,c.length);
|
||||||
|
if (c.indexOf(nameEQ) == 0)
|
||||||
|
value = c.substring(nameEQ.length,c.length);
|
||||||
|
}
|
||||||
|
if(value === last_version){
|
||||||
|
$('#alert-version').parent().hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -31,8 +31,14 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-3 col-md-3 col-sm-2 col-xs-12"></div>
|
<div class="col-lg-3 col-md-3 col-sm-2 col-xs-12"></div>
|
||||||
<div class="col-lg-6 col-md-6 col-sm-8 col-xs-12">
|
<div class="col-lg-6 col-md-6 col-sm-8 col-xs-12">
|
||||||
{% block ante_messages %}{% endblock %}
|
|
||||||
{% if auto_submit %}<noscript>{% endif %}
|
{% if auto_submit %}<noscript>{% endif %}
|
||||||
|
{% if settings.CAS_NEW_VERSION_HTML_WARNING and upgrade_available %}
|
||||||
|
<div class="alert alert-info alert-dismissable">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-hidden="true" id="alert-version">×</button>
|
||||||
|
{% blocktrans %}A new version of the application is available. This instance runs {{VERSION}} and the last version is {{LAST_VERSION}}. Please consider upgrading.{% endblocktrans %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% block ante_messages %}{% endblock %}
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
<div {% spaceless %}
|
<div {% spaceless %}
|
||||||
{% if message.level == message_levels.DEBUG %}
|
{% if message.level == message_levels.DEBUG %}
|
||||||
|
@ -58,5 +64,9 @@
|
||||||
</div> <!-- /container -->
|
</div> <!-- /container -->
|
||||||
<script src="{{settings.CAS_COMPONENT_URLS.jquery}}"></script>
|
<script src="{{settings.CAS_COMPONENT_URLS.jquery}}"></script>
|
||||||
<script src="{{settings.CAS_COMPONENT_URLS.bootstrap3_js}}"></script>
|
<script src="{{settings.CAS_COMPONENT_URLS.bootstrap3_js}}"></script>
|
||||||
|
{% if settings.CAS_NEW_VERSION_HTML_WARNING and upgrade_available %}
|
||||||
|
<script src="{% static "cas_server/alert-version.js" %}"></script>
|
||||||
|
<script>alert_version("{{LAST_VERSION}}")</script>
|
||||||
|
{% endif %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -97,3 +97,6 @@ USE_TZ = True
|
||||||
# https://docs.djangoproject.com/en/1.9/howto/static-files/
|
# https://docs.djangoproject.com/en/1.9/howto/static-files/
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
CAS_NEW_VERSION_HTML_WARNING = False
|
||||||
|
CAS_NEW_VERSION_EMAIL_WARNING = False
|
||||||
|
|
|
@ -16,7 +16,9 @@ import django
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.core import mail
|
||||||
|
|
||||||
|
import mock
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
|
@ -271,3 +273,39 @@ class TicketTestCase(TestCase, UserModels, BaseServicePattern):
|
||||||
)
|
)
|
||||||
self.assertIsNone(ticket._attributs)
|
self.assertIsNone(ticket._attributs)
|
||||||
self.assertIsNone(ticket.attributs)
|
self.assertIsNone(ticket.attributs)
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch("cas_server.utils.last_version", lambda:"1.2.3")
|
||||||
|
@override_settings(ADMINS=[("Ano Nymous", "ano.nymous@example.net")])
|
||||||
|
@override_settings(CAS_NEW_VERSION_EMAIL_WARNING=True)
|
||||||
|
class NewVersionWarningTestCase(TestCase):
|
||||||
|
"""tests for the new version warning model"""
|
||||||
|
|
||||||
|
@mock.patch("cas_server.models.VERSION", "0.1.2")
|
||||||
|
def test_send_mails(self):
|
||||||
|
models.NewVersionWarning.send_mails()
|
||||||
|
|
||||||
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
|
self.assertEqual(
|
||||||
|
mail.outbox[0].subject,
|
||||||
|
'%sA new version of django-cas-server is available' % settings.EMAIL_SUBJECT_PREFIX
|
||||||
|
)
|
||||||
|
|
||||||
|
models.NewVersionWarning.send_mails()
|
||||||
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
|
|
||||||
|
@mock.patch("cas_server.models.VERSION", "1.2.3")
|
||||||
|
def test_send_mails_same_version(self):
|
||||||
|
models.NewVersionWarning.objects.create(version="0.1.2")
|
||||||
|
models.NewVersionWarning.send_mails()
|
||||||
|
self.assertEqual(len(mail.outbox), 0)
|
||||||
|
|
||||||
|
@override_settings(ADMINS=[])
|
||||||
|
def test_send_mails_no_admins(self):
|
||||||
|
models.NewVersionWarning.send_mails()
|
||||||
|
self.assertEqual(len(mail.outbox), 0)
|
||||||
|
|
||||||
|
@override_settings(CAS_NEW_VERSION_EMAIL_WARNING=False)
|
||||||
|
def test_send_mails_disabled(self):
|
||||||
|
models.NewVersionWarning.send_mails()
|
||||||
|
self.assertEqual(len(mail.outbox), 0)
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
from django.test import TestCase, RequestFactory
|
from django.test import TestCase, RequestFactory
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
import warnings
|
||||||
|
|
||||||
from cas_server import utils
|
from cas_server import utils
|
||||||
|
|
||||||
|
@ -208,3 +209,28 @@ class UtilsTestCase(TestCase):
|
||||||
self.assertEqual(utils.get_tuple(test_tuple, 3), None)
|
self.assertEqual(utils.get_tuple(test_tuple, 3), None)
|
||||||
self.assertEqual(utils.get_tuple(test_tuple, 3, 'toto'), 'toto')
|
self.assertEqual(utils.get_tuple(test_tuple, 3, 'toto'), 'toto')
|
||||||
self.assertEqual(utils.get_tuple(None, 3), None)
|
self.assertEqual(utils.get_tuple(None, 3), None)
|
||||||
|
|
||||||
|
def test_last_version(self):
|
||||||
|
"""
|
||||||
|
test the function last_version. An internet connection is needed, if you do not have
|
||||||
|
one, this test will fail and you should ignore it.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# first check if pypi is available
|
||||||
|
utils.requests.get("https://pypi.python.org/simple/django-cas-server/")
|
||||||
|
except utils.requests.exceptions.RequestException:
|
||||||
|
warnings.warn(
|
||||||
|
(
|
||||||
|
"Pypi seems not available, perhaps you do not have internet access. "
|
||||||
|
"Consequently, the test cas_server.tests.test_utils.UtilsTestCase.test_last_"
|
||||||
|
"version is ignored"
|
||||||
|
),
|
||||||
|
RuntimeWarning
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
version = utils.last_version()
|
||||||
|
self.assertIsInstance(version, six.text_type)
|
||||||
|
self.assertEqual(len(version.split('.')), 3)
|
||||||
|
|
||||||
|
# version is cached 24h so calling it a second time should return the save value
|
||||||
|
self.assertEqual(version, utils.last_version())
|
||||||
|
|
|
@ -20,6 +20,7 @@ from django.utils import timezone
|
||||||
|
|
||||||
import random
|
import random
|
||||||
import json
|
import json
|
||||||
|
import mock
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from six.moves import range
|
from six.moves import range
|
||||||
|
|
||||||
|
@ -47,6 +48,28 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin):
|
||||||
# we prepare a bunch a service url and service patterns for tests
|
# we prepare a bunch a service url and service patterns for tests
|
||||||
self.setup_service_patterns()
|
self.setup_service_patterns()
|
||||||
|
|
||||||
|
@override_settings(CAS_NEW_VERSION_HTML_WARNING=True)
|
||||||
|
@mock.patch("cas_server.utils.last_version", lambda:"1.2.3")
|
||||||
|
@mock.patch("cas_server.utils.VERSION", "0.1.2")
|
||||||
|
def test_new_version_available_ok(self):
|
||||||
|
client = Client()
|
||||||
|
response = client.get("/login")
|
||||||
|
self.assertIn(b"A new version of the application is available", response.content)
|
||||||
|
|
||||||
|
@override_settings(CAS_NEW_VERSION_HTML_WARNING=True)
|
||||||
|
@mock.patch("cas_server.utils.last_version", lambda:None)
|
||||||
|
@mock.patch("cas_server.utils.VERSION", "0.1.2")
|
||||||
|
def test_new_version_available_badpypi(self):
|
||||||
|
client = Client()
|
||||||
|
response = client.get("/login")
|
||||||
|
self.assertNotIn(b"A new version of the application is available", response.content)
|
||||||
|
|
||||||
|
@override_settings(CAS_NEW_VERSION_HTML_WARNING=False)
|
||||||
|
def test_new_version_available_disabled(self):
|
||||||
|
client = Client()
|
||||||
|
response = client.get("/login")
|
||||||
|
self.assertNotIn(b"A new version of the application is available", response.content)
|
||||||
|
|
||||||
def test_login_view_post_goodpass_goodlt(self):
|
def test_login_view_post_goodpass_goodlt(self):
|
||||||
"""Test a successul login"""
|
"""Test a successul login"""
|
||||||
# we get a client who fetch a frist time the login page and the login form default
|
# we get a client who fetch a frist time the login page and the login form default
|
||||||
|
|
|
@ -25,11 +25,19 @@ import hashlib
|
||||||
import crypt
|
import crypt
|
||||||
import base64
|
import base64
|
||||||
import six
|
import six
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from six.moves.urllib.parse import urlparse, urlunparse, parse_qsl, urlencode
|
from six.moves.urllib.parse import urlparse, urlunparse, parse_qsl, urlencode
|
||||||
|
|
||||||
|
from . import VERSION
|
||||||
|
|
||||||
|
#: logger facility
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def json_encode(obj):
|
def json_encode(obj):
|
||||||
"""Encode a python object to json"""
|
"""Encode a python object to json"""
|
||||||
|
@ -51,6 +59,16 @@ def context(params):
|
||||||
"""
|
"""
|
||||||
params["settings"] = settings
|
params["settings"] = settings
|
||||||
params["message_levels"] = DEFAULT_MESSAGE_LEVELS
|
params["message_levels"] = DEFAULT_MESSAGE_LEVELS
|
||||||
|
if settings.CAS_NEW_VERSION_HTML_WARNING:
|
||||||
|
LAST_VERSION = last_version()
|
||||||
|
params["VERSION"] = VERSION
|
||||||
|
params["LAST_VERSION"] = LAST_VERSION
|
||||||
|
if LAST_VERSION is not None:
|
||||||
|
t_version = decode_version(VERSION)
|
||||||
|
t_last_version = decode_version(LAST_VERSION)
|
||||||
|
params["upgrade_available"] = t_version < t_last_version
|
||||||
|
else:
|
||||||
|
params["upgrade_available"] = False
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
@ -603,3 +621,51 @@ def check_password(method, password, hashed_password, charset):
|
||||||
)(password).hexdigest().encode("ascii") == hashed_password.lower()
|
)(password).hexdigest().encode("ascii") == hashed_password.lower()
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown password method check %r" % method)
|
raise ValueError("Unknown password method check %r" % method)
|
||||||
|
|
||||||
|
|
||||||
|
def decode_version(version):
|
||||||
|
"""
|
||||||
|
decode a version string following version semantic http://semver.org/ input a tuple of int
|
||||||
|
|
||||||
|
:param unicode version: A dotted version
|
||||||
|
:return: A tuple a int
|
||||||
|
:rtype: tuple
|
||||||
|
"""
|
||||||
|
return tuple(int(sub_version) for sub_version in version.split('.'))
|
||||||
|
|
||||||
|
|
||||||
|
def last_version():
|
||||||
|
"""
|
||||||
|
Fetch the last version from pypi and return it. On successful fetch from pypi, the response
|
||||||
|
is cached 24h, on error, it is cached 10 min.
|
||||||
|
|
||||||
|
:return: the last django-cas-server version
|
||||||
|
:rtype: unicode
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
last_update, version, success = last_version._cache
|
||||||
|
except AttributeError:
|
||||||
|
last_update = 0
|
||||||
|
version = None
|
||||||
|
success = False
|
||||||
|
cache_delta = 24 * 3600 if success else 600
|
||||||
|
if (time.time() - last_update) < cache_delta:
|
||||||
|
return version
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
req = requests.get(settings.CAS_NEW_VERSION_JSON_URL)
|
||||||
|
data = json.loads(req.content)
|
||||||
|
versions = data["releases"].keys()
|
||||||
|
versions.sort()
|
||||||
|
version = versions[-1]
|
||||||
|
last_version._cache = (time.time(), version, True)
|
||||||
|
return version
|
||||||
|
except (
|
||||||
|
KeyError,
|
||||||
|
ValueError,
|
||||||
|
requests.exceptions.RequestException
|
||||||
|
) as error: # pragma: no cover (should not happen unless pypi is not available)
|
||||||
|
logger.error(
|
||||||
|
"Unable to fetch %s: %s" % (settings.CAS_NEW_VERSION_JSON_URL, error)
|
||||||
|
)
|
||||||
|
last_version._cache = (time.time(), version, False)
|
||||||
|
|
|
@ -9,3 +9,4 @@ requests>=2.4
|
||||||
requests_futures>=0.9.5
|
requests_futures>=0.9.5
|
||||||
lxml>=3.4
|
lxml>=3.4
|
||||||
six>=1
|
six>=1
|
||||||
|
mock>=1
|
||||||
|
|
3
setup.py
3
setup.py
|
@ -1,8 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
from cas_server import VERSION
|
||||||
VERSION = '0.6.1'
|
|
||||||
|
|
||||||
with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
|
with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
|
||||||
README = readme.read()
|
README = readme.read()
|
||||||
|
|
Loading…
Reference in a new issue