initial application skeleton
This commit is contained in:
parent
b77dea31a9
commit
d13dbf8178
|
@ -0,0 +1,5 @@
|
||||||
|
*.pyc
|
||||||
|
local_settings.py
|
||||||
|
/db.sqlite3
|
||||||
|
/dist
|
||||||
|
/chrono.egg-info
|
|
@ -0,0 +1,11 @@
|
||||||
|
# locales
|
||||||
|
recursive-include chrono/locale *.po *.mo
|
||||||
|
|
||||||
|
# static
|
||||||
|
|
||||||
|
# templates
|
||||||
|
recursive-include combo/manager/templates *.html
|
||||||
|
|
||||||
|
include COPYING README
|
||||||
|
include MANIFEST.in
|
||||||
|
include VERSION
|
|
@ -0,0 +1,22 @@
|
||||||
|
{% extends "gadjo/base.html" %}
|
||||||
|
{% load staticfiles i18n %}
|
||||||
|
|
||||||
|
{% block page-title %}
|
||||||
|
{% trans 'Agendas' as default_site_title %}
|
||||||
|
{% firstof site_title default_site_title %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block site-title %}
|
||||||
|
{% trans 'Agendas' as default_site_title %}
|
||||||
|
{% firstof site_title default_site_title %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block footer %}Chrono — Copyright © Entr'ouvert{% endblock %}
|
||||||
|
|
||||||
|
{% block homepage-url %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block breadcrumb %}
|
||||||
|
{{ block.super }}
|
||||||
|
<a href="{% url 'chrono-manager-homepage' %}">{% trans 'Agendas' %}</a>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block logout-url %}{% url 'auth_logout' %}{% endblock %}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{% extends "chrono/manager_base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block appbar %}
|
||||||
|
<h2>{% trans 'Agendas' %}</h2>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if object_list %}
|
||||||
|
<div class="objects-list">
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="big-msg-info">
|
||||||
|
{% blocktrans %}
|
||||||
|
This site doesn't have any agenda yet. Click on the "New" button in the top
|
||||||
|
right of the page to add a first one.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{% extends "chrono/manager_base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<input type="submit" value="{% trans 'Log in' %}" />
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,24 @@
|
||||||
|
# chrono - agendas system
|
||||||
|
# Copyright (C) 2016 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = patterns('chrono.views',
|
||||||
|
url(r'^$', views.homepage, name='chrono-manager-homepage'),
|
||||||
|
url(r'^menu.json$', views.menu_json),
|
||||||
|
)
|
|
@ -0,0 +1,44 @@
|
||||||
|
# chrono - agendas system
|
||||||
|
# Copyright (C) 2016 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
|
||||||
|
class HomepageView(TemplateView):
|
||||||
|
template_name = 'chrono/manager_home.html'
|
||||||
|
|
||||||
|
homepage = HomepageView.as_view()
|
||||||
|
|
||||||
|
|
||||||
|
def menu_json(request):
|
||||||
|
response = HttpResponse(content_type='application/json')
|
||||||
|
label = _('Agendas')
|
||||||
|
json_str = json.dumps([{'label': force_text(label),
|
||||||
|
'slug': 'calendar',
|
||||||
|
'url': request.build_absolute_uri(reverse('chrono-manager-homepage'))
|
||||||
|
}])
|
||||||
|
for variable in ('jsonpCallback', 'callback'):
|
||||||
|
if variable in request.GET:
|
||||||
|
json_str = '%s(%s);' % (request.GET[variable], json_str)
|
||||||
|
break
|
||||||
|
response.write(json_str)
|
||||||
|
return response
|
|
@ -0,0 +1,146 @@
|
||||||
|
# chrono - agendas system
|
||||||
|
# Copyright (C) 2016 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Django settings file; it loads the default settings, and local settings
|
||||||
|
(from a local_settings.py file, or a configuration file set in the
|
||||||
|
COMBO_SETTINGS_FILE environment variable).
|
||||||
|
|
||||||
|
The local settings file should exist, at least to set a suitable SECRET_KEY,
|
||||||
|
and to disable DEBUG mode in production.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS, STATICFILES_FINDERS
|
||||||
|
|
||||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = '1am-@xw1d%#+1f+4$ws4e3*k9+z&f4f9i#di4pt4@_%829(%bl'
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
TEMPLATE_DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'gadjo',
|
||||||
|
'chrono.manager',
|
||||||
|
)
|
||||||
|
|
||||||
|
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',
|
||||||
|
)
|
||||||
|
|
||||||
|
TEMPLATE_CONTEXT_PROCESSORS += (
|
||||||
|
'django.core.context_processors.request',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Serve xstatic files, required for gadjo
|
||||||
|
STATICFILES_FINDERS = tuple(STATICFILES_FINDERS) + ('gadjo.finders.XStaticFinder',)
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'chrono.urls'
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'chrono.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/1.7/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'fr-fr'
|
||||||
|
|
||||||
|
TIME_ZONE = 'UTC'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
LOCALE_PATHS = (os.path.join(BASE_DIR, 'chrono', 'locale'), )
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/1.7/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
|
||||||
|
# Authentication settings
|
||||||
|
try:
|
||||||
|
import mellon
|
||||||
|
except ImportError:
|
||||||
|
mellon = None
|
||||||
|
|
||||||
|
if mellon is not None:
|
||||||
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'mellon.backends.SAMLBackend',
|
||||||
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
|
)
|
||||||
|
|
||||||
|
LOGIN_URL = '/login/'
|
||||||
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
LOGOUT_URL = '/logout/'
|
||||||
|
|
||||||
|
MELLON_ATTRIBUTE_MAPPING = {
|
||||||
|
'email': '{attributes[email][0]}',
|
||||||
|
'first_name': '{attributes[first_name][0]}',
|
||||||
|
'last_name': '{attributes[last_name][0]}',
|
||||||
|
}
|
||||||
|
|
||||||
|
MELLON_SUPERUSER_MAPPING = {
|
||||||
|
'is_superuser': 'true',
|
||||||
|
}
|
||||||
|
|
||||||
|
MELLON_USERNAME_TEMPLATE = '{attributes[name_id_content]}'
|
||||||
|
|
||||||
|
MELLON_IDENTITY_PROVIDERS = []
|
||||||
|
|
||||||
|
local_settings_file = os.environ.get('CHRONO_SETTINGS_FILE',
|
||||||
|
os.path.join(os.path.dirname(__file__), 'local_settings.py'))
|
||||||
|
if os.path.exists(local_settings_file):
|
||||||
|
execfile(local_settings_file)
|
|
@ -0,0 +1,42 @@
|
||||||
|
# chrono - agendas system
|
||||||
|
# Copyright (C) 2016 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.conf.urls import patterns, include, url
|
||||||
|
|
||||||
|
from .urls_utils import decorated_includes, manager_required
|
||||||
|
|
||||||
|
from .views import homepage, login, logout
|
||||||
|
from .manager.urls import urlpatterns as chrono_manager_urls
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^$', homepage, name='home'),
|
||||||
|
url(r'^manage/', decorated_includes(manager_required,
|
||||||
|
include(chrono_manager_urls))),
|
||||||
|
url(r'^logout/$', logout, name='auth_logout'),
|
||||||
|
url(r'^login/$', login, name='auth_login'),
|
||||||
|
)
|
||||||
|
|
||||||
|
if 'mellon' in settings.INSTALLED_APPS:
|
||||||
|
urlpatterns += patterns('', url(r'^accounts/mellon/', include('mellon.urls')))
|
||||||
|
|
||||||
|
# static and media files
|
||||||
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
|
urlpatterns += staticfiles_urlpatterns()
|
||||||
|
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
|
@ -0,0 +1,62 @@
|
||||||
|
# chrono - agendas system
|
||||||
|
# Copyright (C) 2016 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# Decorating URL includes, <https://djangosnippets.org/snippets/2532/>
|
||||||
|
|
||||||
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
|
||||||
|
|
||||||
|
class DecoratedURLPattern(RegexURLPattern):
|
||||||
|
def resolve(self, *args, **kwargs):
|
||||||
|
result = super(DecoratedURLPattern, self).resolve(*args, **kwargs)
|
||||||
|
if result:
|
||||||
|
result.func = self._decorate_with(result.func)
|
||||||
|
return result
|
||||||
|
|
||||||
|
class DecoratedRegexURLResolver(RegexURLResolver):
|
||||||
|
def resolve(self, *args, **kwargs):
|
||||||
|
result = super(DecoratedRegexURLResolver, self).resolve(*args, **kwargs)
|
||||||
|
if result:
|
||||||
|
result.func = self._decorate_with(result.func)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def decorated_includes(func, includes, *args, **kwargs):
|
||||||
|
urlconf_module, app_name, namespace = includes
|
||||||
|
|
||||||
|
for item in urlconf_module:
|
||||||
|
if isinstance(item, RegexURLPattern):
|
||||||
|
item.__class__ = DecoratedURLPattern
|
||||||
|
item._decorate_with = func
|
||||||
|
|
||||||
|
elif isinstance(item, RegexURLResolver):
|
||||||
|
item.__class__ = DecoratedRegexURLResolver
|
||||||
|
item._decorate_with = func
|
||||||
|
|
||||||
|
return urlconf_module, app_name, namespace
|
||||||
|
|
||||||
|
def manager_required(function=None, login_url=None):
|
||||||
|
def check_manager(user):
|
||||||
|
if user and user.is_staff:
|
||||||
|
return True
|
||||||
|
if user and not user.is_anonymous():
|
||||||
|
raise PermissionDenied()
|
||||||
|
# As the last resort, show the login form
|
||||||
|
return False
|
||||||
|
actual_decorator = user_passes_test(check_manager, login_url=login_url)
|
||||||
|
if function:
|
||||||
|
return actual_decorator(function)
|
||||||
|
return actual_decorator
|
|
@ -0,0 +1,49 @@
|
||||||
|
# chrono - agendas system
|
||||||
|
# Copyright (C) 2016 Entr'ouvert
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Affero General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
from django.contrib.auth import logout as auth_logout
|
||||||
|
from django.contrib.auth import views as auth_views
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import resolve_url
|
||||||
|
|
||||||
|
try:
|
||||||
|
from mellon.utils import get_idps
|
||||||
|
except ImportError:
|
||||||
|
get_idps = lambda: []
|
||||||
|
|
||||||
|
|
||||||
|
def login(request, *args, **kwargs):
|
||||||
|
if any(get_idps()):
|
||||||
|
if not 'next' in request.GET:
|
||||||
|
return HttpResponseRedirect(resolve_url('mellon_login'))
|
||||||
|
return HttpResponseRedirect(resolve_url('mellon_login') + '?next='
|
||||||
|
+ urllib.quote(request.GET.get('next')))
|
||||||
|
return auth_views.login(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def logout(request, next_page=None):
|
||||||
|
if any(get_idps()):
|
||||||
|
return HttpResponseRedirect(resolve_url('mellon_logout'))
|
||||||
|
auth_logout(request)
|
||||||
|
if next_page is not None:
|
||||||
|
next_page = resolve_url(next_page)
|
||||||
|
else:
|
||||||
|
next_page = '/'
|
||||||
|
return HttpResponseRedirect(next_page)
|
||||||
|
|
||||||
|
def homepage(request, *args, **kwargs):
|
||||||
|
return HttpResponseRedirect(resolve_url('chrono-manager-homepage'))
|
|
@ -0,0 +1,14 @@
|
||||||
|
"""
|
||||||
|
WSGI config for chrono project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "chrono.settings")
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
application = get_wsgi_application()
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "chrono.settings")
|
||||||
|
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
execute_from_command_line(sys.argv)
|
|
@ -0,0 +1,115 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from setuptools.command.install_lib import install_lib as _install_lib
|
||||||
|
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
|
||||||
|
|
||||||
|
class eo_sdist(sdist):
|
||||||
|
def run(self):
|
||||||
|
if os.path.exists('VERSION'):
|
||||||
|
os.remove('VERSION')
|
||||||
|
version = get_version()
|
||||||
|
version_file = open('VERSION', 'w')
|
||||||
|
version_file.write(version)
|
||||||
|
version_file.close()
|
||||||
|
sdist.run(self)
|
||||||
|
if os.path.exists('VERSION'):
|
||||||
|
os.remove('VERSION')
|
||||||
|
|
||||||
|
def get_version():
|
||||||
|
if os.path.exists('VERSION'):
|
||||||
|
version_file = open('VERSION', 'r')
|
||||||
|
version = version_file.read()
|
||||||
|
version_file.close()
|
||||||
|
return version
|
||||||
|
if os.path.exists('.git'):
|
||||||
|
p = subprocess.Popen(['git', 'describe', '--dirty', '--match=v*'], stdout=subprocess.PIPE)
|
||||||
|
result = p.communicate()[0]
|
||||||
|
if p.returncode == 0:
|
||||||
|
version = result.split()[0][1:]
|
||||||
|
version = version.replace('-', '.')
|
||||||
|
return version
|
||||||
|
return '0'
|
||||||
|
|
||||||
|
def data_tree(destdir, sourcedir):
|
||||||
|
extensions = ['.css', '.png', '.jpeg', '.jpg', '.gif', '.xml', '.html', '.js']
|
||||||
|
r = []
|
||||||
|
for root, dirs, files in os.walk(sourcedir):
|
||||||
|
l = [os.path.join(root, x) for x in files if os.path.splitext(x)[1] in extensions]
|
||||||
|
r.append((root.replace(sourcedir, destdir, 1), l))
|
||||||
|
return r
|
||||||
|
|
||||||
|
class compile_translations(Command):
|
||||||
|
description = 'compile message catalogs to MO files via django compilemessages'
|
||||||
|
user_options = []
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
from django.core.management import call_command
|
||||||
|
for path, dirs, files in os.walk('chrono'):
|
||||||
|
if 'locale' not in dirs:
|
||||||
|
continue
|
||||||
|
curdir = os.getcwd()
|
||||||
|
os.chdir(os.path.realpath(path))
|
||||||
|
call_command('compilemessages')
|
||||||
|
os.chdir(curdir)
|
||||||
|
except ImportError:
|
||||||
|
sys.stderr.write('!!! Please install Django >= 1.4 to build translations\n')
|
||||||
|
|
||||||
|
|
||||||
|
class build(_build):
|
||||||
|
sub_commands = [('compile_translations', None)] + _build.sub_commands
|
||||||
|
|
||||||
|
|
||||||
|
class install_lib(_install_lib):
|
||||||
|
def run(self):
|
||||||
|
self.run_command('compile_translations')
|
||||||
|
_install_lib.run(self)
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='chrono',
|
||||||
|
version=get_version(),
|
||||||
|
description='Agendas System',
|
||||||
|
author='Frederic Peters',
|
||||||
|
author_email='fpeters@entrouvert.com',
|
||||||
|
packages=find_packages(),
|
||||||
|
include_package_data=True,
|
||||||
|
scripts=('manage.py',),
|
||||||
|
url='https://dev.entrouvert.org/projects/chrono/',
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 2 - Pre-Alpha',
|
||||||
|
'Environment :: Web Environment',
|
||||||
|
'Framework :: Django',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'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.7, <1.8',
|
||||||
|
'gadjo',
|
||||||
|
],
|
||||||
|
zip_safe=False,
|
||||||
|
cmdclass={
|
||||||
|
'build': build,
|
||||||
|
'compile_translations': compile_translations,
|
||||||
|
'install_lib': install_lib,
|
||||||
|
'sdist': eo_sdist,
|
||||||
|
},
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
|
@ -0,0 +1,40 @@
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
import pytest
|
||||||
|
from webtest import TestApp
|
||||||
|
|
||||||
|
from chrono.wsgi import application
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def admin_user():
|
||||||
|
try:
|
||||||
|
user = User.objects.get(username='admin')
|
||||||
|
except User.DoesNotExist:
|
||||||
|
user = User.objects.create_superuser('admin', email=None, password='admin')
|
||||||
|
return user
|
||||||
|
|
||||||
|
def login(app, username='admin', password='admin'):
|
||||||
|
login_page = app.get('/login/')
|
||||||
|
login_form = login_page.forms[0]
|
||||||
|
login_form['username'] = username
|
||||||
|
login_form['password'] = password
|
||||||
|
resp = login_form.submit()
|
||||||
|
assert resp.status_int == 302
|
||||||
|
return app
|
||||||
|
|
||||||
|
def test_unlogged_access():
|
||||||
|
# connect while not being logged in
|
||||||
|
app = TestApp(application)
|
||||||
|
assert app.get('/manage/', status=302).location == 'http://localhost:80/login/?next=/manage/'
|
||||||
|
|
||||||
|
def test_access(admin_user):
|
||||||
|
app = login(TestApp(application))
|
||||||
|
resp = app.get('/manage/', status=200)
|
||||||
|
assert '<h2>Agendas</h2>' in resp.body
|
||||||
|
assert "This site doesn't have any agenda yet." in resp.body
|
||||||
|
|
||||||
|
def test_logout(admin_user):
|
||||||
|
app = login(TestApp(application))
|
||||||
|
app.get('/logout/')
|
||||||
|
assert app.get('/manage/', status=302).location == 'http://localhost:80/login/?next=/manage/'
|
Loading…
Reference in New Issue