Merge remote-tracking branch 'origin/master'
authorMaciej Tronowski <mtro@man.poznan.pl>
Fri, 27 Feb 2015 16:17:15 +0000 (17:17 +0100)
committerMaciej Tronowski <mtro@man.poznan.pl>
Fri, 27 Feb 2015 16:17:15 +0000 (17:17 +0100)
# Conflicts:
# plgng/settings.py
# qcg/forms.py
# qcg/views.py

plgng/local.py [new file with mode: 0644]
plgng/settings.py
plgng/settings_common.py [new file with mode: 0644]
plgng/settings_prod.py [new file with mode: 0644]
qcg/forms.py
qcg/templates/qcg/jobs.html
qcg/views.py
requirements_dev.txt [new file with mode: 0644]

diff --git a/plgng/local.py b/plgng/local.py
new file mode 100644 (file)
index 0000000..ca8c272
--- /dev/null
@@ -0,0 +1,8 @@
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = ''
+
+ALLOWED_HOSTS = ['']
+
+# database credentials
+DATABASE_USER = ''
+DATABASE_PASS = ''
\ No newline at end of file
index 6679cb1..ba04fd0 100644 (file)
@@ -1,71 +1,11 @@
-"""
-Django settings for plgng project.
+from settings_common import *
 
-For more information on this file, see
-https://docs.djangoproject.com/en/1.7/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/1.7/ref/settings/
-"""
-
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-import os
-
-import django.conf.global_settings as defaults
-
-
-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 = 'x%_rlnhibsxum1m5o_c5ac@p0nw+1r0&#k!v3+52)s(d=2$5y&'
 
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = True
-
 TEMPLATE_DEBUG = True
 
-ALLOWED_HOSTS = []
-
-
-# Application definition
-
-INSTALLED_APPS = (
-    'grappelli',
-    'django.contrib.admin',
-    'django.contrib.auth',
-    'django.contrib.contenttypes',
-    'django.contrib.sessions',
-    'django.contrib.messages',
-    'django.contrib.staticfiles',
-    'django.contrib.webdesign',
-    'qcg',
-    'django_openid_auth',
-    'bootstrap3',
-)
-
-MIDDLEWARE_CLASSES = (
-    'django.contrib.sessions.middleware.SessionMiddleware',
-    'django.middleware.common.CommonMiddleware',
-    'django.middleware.csrf.CsrfViewMiddleware',
-    'django.contrib.auth.middleware.AuthenticationMiddleware',
-    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
-    'django.contrib.messages.middleware.MessageMiddleware',
-    'django.middleware.clickjacking.XFrameOptionsMiddleware',
-)
-
-TEMPLATE_CONTEXT_PROCESSORS = defaults.TEMPLATE_CONTEXT_PROCESSORS + (
-    'django.core.context_processors.request',
-)
-
-ROOT_URLCONF = 'plgng.urls'
-
-WSGI_APPLICATION = 'plgng.wsgi.application'
-
-
 # Database
 # https://docs.djangoproject.com/en/1.7/ref/settings/#databases
 
@@ -76,63 +16,4 @@ DATABASES = {
     }
 }
 
-# Internationalization
-# https://docs.djangoproject.com/en/1.7/topics/i18n/
-
-LANGUAGE_CODE = 'pl'
-
-TIME_ZONE = 'Europe/Warsaw'
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-
-CUSTOM_DATETIME_FORMAT = 'j b Y, H:i'
-
-
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/1.7/howto/static-files/
-
-STATIC_URL = '/static/'
-
-
-# Authentication
-
-AUTH_USER_MODEL = 'qcg.User'
-
-AUTHENTICATION_BACKENDS = (
-    'django_openid_auth.auth.OpenIDBackend',
-    'django.contrib.auth.backends.ModelBackend',
-)
-
-LOGIN_URL = 'openid-login'
-LOGIN_REDIRECT_URL = '/jobs/'
-
-# If set, always use this as the identity URL rather than asking the
-# user.  This only makes sense if it is a server URL.
-OPENID_SSO_SERVER_URL = 'https://openid.plgrid.pl/gateway'
-
-# Should users be created when new OpenIDs are used to log in?
-OPENID_CREATE_USERS = True
-
-# Update user details from OpenID each time they log in
-OPENID_UPDATE_DETAILS_FROM_SREG = True
-
-# Login will fail if no 'nickname' (username), or if the nickname
-# conflicts with an existing user with a different openid identity url
-OPENID_STRICT_USERNAMES = True
-
-
-SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
-
-
-# 3-rd party settings
-
-BOOTSTRAP3 = {
-    'horizontal_label_class': 'col-sm-3 col-md-4',
-    'horizontal_field_class': 'col-sm-9 col-md-6',
-    'set_placeholder': False,
-}
+DEBUG_TOOLBAR_CONFIG = {'JQUERY_URL': ''}
\ No newline at end of file
diff --git a/plgng/settings_common.py b/plgng/settings_common.py
new file mode 100644 (file)
index 0000000..0127218
--- /dev/null
@@ -0,0 +1,116 @@
+"""
+Django settings for plgng project.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.7/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.7/ref/settings/
+"""
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+
+import django.conf.global_settings as defaults
+
+from local import *
+
+BASE_DIR = os.path.dirname(os.path.dirname(__file__))
+
+
+# Application definition
+
+INSTALLED_APPS = (
+    'grappelli',
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'django.contrib.webdesign',
+    'qcg',
+    'django_openid_auth',
+    'bootstrap3',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+)
+
+TEMPLATE_CONTEXT_PROCESSORS = defaults.TEMPLATE_CONTEXT_PROCESSORS + (
+    'django.core.context_processors.request',
+)
+
+ROOT_URLCONF = 'plgng.urls'
+
+WSGI_APPLICATION = 'plgng.wsgi.application'
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.7/topics/i18n/
+
+LANGUAGE_CODE = 'pl'
+
+TIME_ZONE = 'Europe/Warsaw'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+CUSTOM_DATETIME_FORMAT = 'j b Y, H:i'
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.7/howto/static-files/
+
+STATIC_URL = '/static/'
+
+
+# Authentication
+
+AUTH_USER_MODEL = 'qcg.User'
+
+AUTHENTICATION_BACKENDS = (
+    'django_openid_auth.auth.OpenIDBackend',
+    'django.contrib.auth.backends.ModelBackend',
+)
+
+LOGIN_URL = 'openid-login'
+LOGIN_REDIRECT_URL = '/jobs/'
+
+# If set, always use this as the identity URL rather than asking the
+# user.  This only makes sense if it is a server URL.
+OPENID_SSO_SERVER_URL = 'https://openid.plgrid.pl/gateway'
+
+# Should users be created when new OpenIDs are used to log in?
+OPENID_CREATE_USERS = True
+
+# Update user details from OpenID each time they log in
+OPENID_UPDATE_DETAILS_FROM_SREG = True
+
+# Login will fail if no 'nickname' (username), or if the nickname
+# conflicts with an existing user with a different openid identity url
+OPENID_STRICT_USERNAMES = True
+
+
+SESSION_COOKIE_NAME = 'qcg_session'
+SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
+
+
+# 3-rd party settings
+
+BOOTSTRAP3 = {
+    'horizontal_label_class': 'col-md-4',
+    'horizontal_field_class': 'col-md-6',
+    'set_placeholder': False,
+}
\ No newline at end of file
diff --git a/plgng/settings_prod.py b/plgng/settings_prod.py
new file mode 100644 (file)
index 0000000..819c296
--- /dev/null
@@ -0,0 +1,20 @@
+from settings_common import *
+
+SESSION_COOKIE_SECURE = True
+CSRF_COOKIE_SECURE = True
+
+# Database
+# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.postgresql_psycopg2',
+        'NAME': 'baza',
+        'USER': DATABASE_USER,
+        'PASSWORD': DATABASE_PASS,
+        'HOST': 'localhost',
+        'PORT': '5432',
+    },
+}
+
+STATIC_ROOT = 'server-static'
\ No newline at end of file
index 1771327..83a053a 100644 (file)
@@ -169,3 +169,19 @@ class EnvForm(forms.Form):
 
 
 EnvFormSet = forms.formset_factory(EnvForm, can_delete=True, extra=0)
+
+
+class ColumnsForm(forms.Form):
+    JOB_ID, DESCRIPTION, SUBMISSION, START, END, STATUS, HOST = range(7)
+    COLUMNS_CHOICES = (
+        (JOB_ID, u"Identyfikator zadania"),
+        (DESCRIPTION, u"Opis"),
+        (SUBMISSION, u"Wysłane"),
+        (START, u"Start"),
+        (END, u"Koniec"),
+        (STATUS, u"Status"),
+        (HOST, u"Host"),
+    )
+
+    columns = forms.MultipleChoiceField(choices=COLUMNS_CHOICES, label=u"Kolumny", required=False,
+                                        widget=forms.CheckboxSelectMultiple)
index 9f55914..9f184e7 100644 (file)
@@ -20,6 +20,7 @@
     <script src="{% static 'qcg/treegrid/js/jquery.treegrid.js' %}"></script>
     <script src="{% static 'qcg/moment/moment.min.js' %}"></script>
     <script src="{% static 'qcg/daterangepicker/daterangepicker.js' %}"></script>
+    <script src="{% static 'qcg/jquery.cookie.js' %}"></script>
 
     <script>
         $(function() {
                     firstDay: 1
                 }
             });
+
+            $('#select-all-columns').click(function() {
+                $('#id_columns').find('.checkbox input').prop('checked', true);
+            });
+
+            $('#default-columns').click(function() {
+                $('#select-all-columns').click();
+                $('#id_columns_0').prop('checked', false);
+            });
+
+            $('#columns-form').submit(function(e) {
+                e.preventDefault();
+                $.cookie.raw = true;
+                $.cookie('columns', $(this).serialize(), {path: location.pathname});
+                location.reload();
+            });
         });
     </script>
 {% endblock %}
         <a href="#advanced" data-toggle="modal" class="btn btn-default" title="Filtry zaawansowane" style="margin-left: 4px">
             <span class="glyphicon glyphicon-option-horizontal"></span>
         </a>
+        <a href="#columns" data-toggle="modal" class="btn btn-default" title="Kolumny" style="margin-left: 4px">
+            <span class="glyphicon glyphicon-list"></span>
+        </a>
     </form>
 
     <h1 class="page-header">
         <thead>
             <tr>
                 <th style="width: 80px"></th>
-                <th>Opis</th>
-                <th>Wysłane</th>
-                <th>Start</th>
-                <th>Koniec</th>
-                <th>Status</th>
-                <th>Host</th>
+                {% if columns.DESCRIPTION in displayed %}<th>Opis</th>{% endif %}
+                {% if columns.SUBMISSION in displayed %}<th>Wysłane</th>{% endif %}
+                {% if columns.START in displayed %}<th>Start</th>{% endif %}
+                {% if columns.END in displayed %}<th>Koniec</th>{% endif %}
+                {% if columns.STATUS in displayed %}<th>Status</th>{% endif %}
+                {% if columns.HOST in displayed %}<th>Host</th>{% endif %}
                 <th></th>
 {#                <th>Uwagi</th>#}
             </tr>
                             <td>
                                 <a href="{{ task.get_absolute_url }}">
                                     <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
-{#                                    {{ task }}#}
+                                    {% if columns.JOB_ID in displayed %}{{ task }}{% endif %}
                                 </a>
                             </td>
-                            <td>{{ task.note }}</td>
-                            <td>{{ task.submission_time|timesince }} temu</td>
-                            <td>{{ task.start_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>
-                            <td>{{ task.finish_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>
-                            <td>{{ task.get_status_display }}</td>
-                            <td>{{ task.short_host_names|join:', ' }}</td>
+                            {% if columns.DESCRIPTION in displayed %}<td>{{ task.note }}</td>{% endif %}
+                            {% if columns.SUBMISSION in displayed %}<td>{{ task.submission_time|timesince }} temu</td>{% endif %}
+                            {% if columns.START in displayed %}<td>{{ task.start_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>{% endif %}
+                            {% if columns.END in displayed %}<td>{{ task.finish_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>{% endif %}
+                            {% if columns.STATUS in displayed %}<td>{{ task.get_status_display }}</td>{% endif %}
+                            {% if columns.HOST in displayed %}<td>{{ task.short_host_names|join:', ' }}</td>{% endif %}
                             <td><a href="{{ task.get_absolute_url }}">szczegóły&nbsp;&rsaquo;</a></td>
                         </tr>
                     {% endwith %}
                         <td>
                             <a href="{{ job.grouper.get_absolute_url }}">
                                 <span class="glyphicon glyphicon-folder-close" aria-hidden="true"></span>
-{#                                {{ job.grouper }}#}
+                                {% if columns.JOB_ID in displayed %}{{ job.grouper }}{% endif %}
                             </a>
                         </td>
-                        <td>{{ job.grouper.note }}</td>
-                        <td>{{ job.grouper.submission_time|timesince  }} temu</td>
-                        <td>-</td>
-                        <td>{{ job.grouper.finish_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>
-                        <td>{{ job.grouper.get_status_display }}</td>
-                        <td>-</td>
+                        {% if columns.DESCRIPTION in displayed %}<td>{{ job.grouper.note }}</td>{% endif %}
+                        {% if columns.SUBMISSION in displayed %}<td>{{ job.grouper.submission_time|timesince  }} temu</td>{% endif %}
+                        {% if columns.START in displayed %}<td>-</td>{% endif %}
+                        {% if columns.END in displayed %}<td>{{ job.grouper.finish_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>{% endif %}
+                        {% if columns.STATUS in displayed %}<td>{{ job.grouper.get_status_display }}</td>{% endif %}
+                        {% if columns.HOST in displayed %}<td>-</td>{% endif %}
                         <td><a href="{{ job.grouper.get_absolute_url }}">szczegóły&nbsp;&rsaquo;</a></td>
                     </tr>
 
                             <td>
                                 <a href="{{ task.get_absolute_url }}">
                                     <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
-{#                                    {{ task }}#}
+                                    {% if columns.JOB_ID in displayed %}{{ task }}{% endif %}
                                 </a>
                             </td>
-                            <td>{{ task.note }}</td>
-                            <td>{{ task.submission_time|timesince  }} temu</td>
-                            <td>{{ task.start_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>
-                            <td>{{ task.finish_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>
-                            <td>{{ task.get_status_display }}</td>
-                            <td>{{ task.short_host_names|join:', ' }}</td>
+                            {% if columns.DESCRIPTION in displayed %}<td>{{ task.note }}</td>{% endif %}
+                            {% if columns.SUBMISSION in displayed %}<td>{{ task.submission_time|timesince  }} temu</td>{% endif %}
+                            {% if columns.START in displayed %}<td>{{ task.start_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>{% endif %}
+                            {% if columns.END in displayed %}<td>{{ task.finish_time|date:"CUSTOM_DATETIME_FORMAT" }}</td>{% endif %}
+                            {% if columns.STATUS in displayed %}<td>{{ task.get_status_display }}</td>{% endif %}
+                            {% if columns.HOST in displayed %}<td>{{ task.short_host_names|join:', ' }}</td>{% endif %}
                             <td><a href="{{ task.get_absolute_url }}">szczegóły&nbsp;&rsaquo;</a></td>
                         </tr>
                     {% endfor %}
         </div>
     </div>
 
+    {# Column selection modal #}
+    <div class="modal fade" id="columns" tabindex="-1" role="dialog" aria-labelledby="modal-label" aria-hidden="true">
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title" id="modal-label">Wybór kolumn</h4>
+                </div>
+                <div class="modal-body">
+                    <form id="columns-form" action=".">
+                        {% bootstrap_field columns.columns %}
+                    </form>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
+                    <a id="select-all-columns" class="btn btn-success">Wybierz wszystkie</a>
+                    <a id="default-columns" class="btn btn-warning">Domyślne</a>
+                    <button type="submit" class="btn btn-primary" form="columns-form">Zapisz</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
 {% endblock container %}
index f0de4dc..7a8f351 100644 (file)
@@ -5,7 +5,7 @@ from django.contrib.auth import REDIRECT_FIELD_NAME
 from django.contrib.auth.decorators import login_required
 from django.core.urlresolvers import reverse
 from django.db.models import Q
-from django.http import HttpResponse
+from django.http import HttpResponse, QueryDict
 from django.shortcuts import render, get_object_or_404
 from django.utils.http import urlencode
 from django.utils.timezone import UTC
@@ -13,7 +13,7 @@ from django_openid_auth.views import make_consumer
 from openid.extensions import ax
 from pyqcg import QCG
 
-from qcg.forms import FiltersForm, JobDescriptionForm, EnvFormSet
+from qcg.forms import FiltersForm, ColumnsForm, JobDescriptionForm, EnvFormSet
 from qcg.utils import update_user_data, paginator_context
 
 
@@ -115,7 +115,17 @@ def jobs_list(request):
 
     checked_status = {i: widget.is_checked() for i, widget in enumerate(filters['status'])}
 
-    context = {'filters': filters, 'checked_status': checked_status, 'selected_filters': selected_filters}
+    if 'columns' in request.COOKIES:
+        columns = ColumnsForm(QueryDict(request.COOKIES.get('columns')))
+
+    if 'columns' not in request.COOKIES or not columns.is_valid():
+        columns = ColumnsForm(QueryDict('columns=1&columns=2&columns=3&columns=4&columns=5&columns=6'))
+        columns.is_valid()
+
+    context = {'filters': filters, 'checked_status': checked_status, 'selected_filters': selected_filters,
+               'columns': ColumnsForm(initial={'columns': columns.cleaned_data['columns']}),
+               'displayed': {int(c) for c in columns.cleaned_data['columns']}}
+
     context.update(paginator_context(request, tasks))
 
     return render(request, 'qcg/jobs.html', context)
diff --git a/requirements_dev.txt b/requirements_dev.txt
new file mode 100644 (file)
index 0000000..64eaf2e
--- /dev/null
@@ -0,0 +1,3 @@
+-r requirements.txt
+django-sslserver
+django-debug-toolbar
\ No newline at end of file