--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('qcg', '0003_jobtemplate'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='job',
+ name='description_type',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Typ opisu', choices=[(0, b'JSDL'), (1, b'QCG'), (2, b'QCG_SIMPLE')]),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='job',
+ name='qcg_description',
+ field=models.TextField(default=b'', verbose_name='Opis QCG', blank=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='task',
+ name='description_type',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Typ opisu', choices=[(0, b'JSDL'), (1, b'QCG'), (2, b'QCG_SIMPLE')]),
+ preserve_default=True,
+ ),
+ ]
from django.db import models
from django.utils.timezone import now
from pyqcg.service import Job as QcgJob, Task as QcgTask
-from pyqcg.utils import JobStatus, TaskStatus, TaskType, AllocationType, EPRUtils
+from pyqcg.utils import JobStatus, TaskStatus, TaskType, AllocationType, EPRUtils, DescriptionType
from qcg.utils import username_from_dn, get_attributes
return Task.objects.filter(job__owner=self)
+DESC_TYPE_CHOICES = list(enumerate(field for field in dir(DescriptionType) if not field.startswith('__')))
+DESC_TYPE_CHOICES_REVERSED = {v: k for k, v in DESC_TYPE_CHOICES}
+
+
class Job(models.Model):
STATUS_CHOICES = list(enumerate(field for field in dir(JobStatus) if not field.startswith('__')))
STATUS_CHOICES_REVERSED = {v: k for k, v in STATUS_CHOICES}
status = models.IntegerField(u"Status", choices=STATUS_CHOICES)
note = models.TextField(u"Notatka", blank=True, default='')
description = models.TextField(u"Opis", blank=True, default='')
+ description_type = models.IntegerField(u"Typ opisu", choices=DESC_TYPE_CHOICES, blank=True, null=True)
+ qcg_description = models.TextField(u"Opis QCG", blank=True, default='')
project = models.TextField(u"Projekt", blank=True, default='')
submission_time = models.DateTimeField(u"Data wysłania")
finish_time = models.DateTimeField(u"Data zakończenia", blank=True, null=True)
@staticmethod
def qcg_map(qcg_job, user=None):
- attrs = get_attributes(qcg_job, ('job_id', 'note', 'description', 'submission_time', 'finish_time',
- 'project', 'purged'))
+ attrs = get_attributes(qcg_job, ('job_id', 'note', 'description', 'qcg_description', 'submission_time',
+ 'finish_time', 'project', 'purged'))
attrs['epr'] = EPRUtils.serialize_epr(qcg_job.epr)
attrs['status'] = Job.STATUS_CHOICES_REVERSED[qcg_job.status]
+ attrs['description_type'] = DESC_TYPE_CHOICES_REVERSED[qcg_job.description_type]
attrs['proxy_lifetime'] = now() + qcg_job.proxy_lifetime
username = username_from_dn(qcg_job.user_dn)
type = models.IntegerField(u"Typ", choices=TYPE_CHOICES)
note = models.TextField(u"Notatka", blank=True, default='')
description = models.TextField(u"Opis", blank=True, default='')
+ description_type = models.IntegerField(u"Typ opisu", choices=DESC_TYPE_CHOICES, blank=True, null=True)
submission_time = models.DateTimeField(u"Data wysłania")
start_time = models.DateTimeField(u"Data rozpoczęcia", blank=True, null=True)
finish_time = models.DateTimeField(u"Data zakończenia", blank=True, null=True)
attrs['epr'] = EPRUtils.serialize_epr(qcg_task.epr)
attrs['status'] = Task.STATUS_CHOICES_REVERSED[qcg_task.status]
attrs['type'] = Task.TYPE_CHOICES_REVERSED[qcg_task.type]
+ attrs['description_type'] = DESC_TYPE_CHOICES_REVERSED[qcg_task.description_type]
attrs['proxy_lifetime'] = now() + qcg_task.proxy_lifetime
if job is not None:
{% extends 'qcg/base.html' %}
-{% load qcg_utils %}
+{% load qcg_utils bootstrap3 %}
{% block container %}
<ol class="breadcrumb">
</div>
<div role="tabpanel" class="tab-pane" id="desc">
- <pre>{{ job.description }}</pre>
+ <button class="btn btn-default btn-sm pull-right" data-toggle="modal" data-target="#template">Zapisz jako szablon</button>
+
+ {% if job.get_description_type_display != 'QCG' %}
+ <h3>Opis użytkownika</h3>
+ <pre>{{ job.description }}</pre>
+ {% endif %}
+
+ <h3>Opis QCG</h3>
+ <pre>{{ job.qcg_description|format_xml }}</pre>
</div>
</div>
</div>
+ <form id="template" action="{% url 'job_save_template' job.job_id %}" method="post" class="modal fade form-horizontal" tabindex="-1"
+ role="dialog" aria-labelledby="template-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">×</span></button>
+ <h4 class="modal-title" id="template-modal-label">Podaj nazwę szablonu</h4>
+ </div>
+ <div class="modal-body">
+ {% csrf_token %}
+ {% bootstrap_field template_form.name layout="horizontal" %}
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
+ <button type="submit" class="btn btn-primary" data-loading-text="Zapisywanie...">Zapisz</button>
+ </div>
+ </div>
+ </div>
+ </form>
+
{% endblock container %}
from datetime import datetime, timedelta
+from pyexpat import ExpatError
from xml.dom import minidom
from django import template
@register.filter(needs_autoescape=True)
def format_xml(string, autoescape=None):
esc = conditional_escape if autoescape else lambda x: x
- return esc(minidom.parseString(string).toprettyxml(indent=' '))
+ try:
+ return esc(minidom.parseString(string).toprettyxml(indent=' '))
+ except ExpatError:
+ return string
url(r'^job/cancel/(?P<job_id>[\w]+)/$', views.job_cancel, name='job_cancel'),
url(r'^job/clean/(?P<job_id>[\w]+)/$', views.job_clean, name='job_clean'),
+ url(r'^job/save/template/(?P<job_id>[\w]+)/$', views.job_save_template, name='job_save_template'),
url(r'^task/cancel/(?P<job_id>[\w]+)/(?P<task_id>[\w]+)/$', views.task_cancel, name='task_cancel'),
url(r'^task/clean/(?P<job_id>[\w]+)/(?P<task_id>[\w]+)/$', views.task_clean, name='task_clean'),
from filex.ftp import FTPOperation, FTPError
from filex.views import make_url
from qcg.forms import FiltersForm, ColumnsForm, JobDescriptionForm, EnvFormSet, JobTemplateForm
+from qcg.models import JobTemplate
from qcg.utils import paginator_context, to_job_desc, to_form_data
from qcg.service import update_user_data, update_job, cancel, clean
update_job(job, request.session['proxy'])
- return render(request, 'qcg/job.html', {'job': job})
+ template_form = JobTemplateForm(initial={'name': job.note or u'Szablon z {}'.format(job.job_id)})
+
+ return render(request, 'qcg/job.html', {'job': job, 'template_form': template_form})
@login_required
'Usunięto szablon <em>{}</em>.', template.name))
return redirect('job_templates')
+
+
+@require_POST
+@login_required
+def job_save_template(request, job_id):
+ job = get_object_or_404(request.user.jobs, job_id=job_id)
+
+ template_form = JobTemplateForm(request.POST,
+ instance=JobTemplate(owner=request.user, description=job.qcg_description))
+
+ if template_form.is_valid():
+ template = template_form.save()
+
+ return redirect(template)
+
+ messages.error(request, format_html('<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> {}'
+ 'Nie udało się zapisać szablonu!', template_form.errors))
+
+ return redirect(job)
django-grappelli
django-bootstrap3
pkgs/django-openid-auth-0.5.1.tar.gz
-pkgs/pyqcg-0.6.tar.gz
+pkgs/pyqcg-0.6.1.tar.gz
pkgs/python-gridftp-1.3.4.tar.gz
python-openid
pytz