Importer: Adapt contribution/subcontribution creation

This commit is contained in:
Florian Vessaz 2016-04-11 13:41:15 +02:00
parent ae9be2ebb4
commit b60e2389dc
3 changed files with 211 additions and 40 deletions

View File

@ -16,9 +16,17 @@
from __future__ import unicode_literals
from datetime import datetime
from dateutil.relativedelta import relativedelta
from flask import jsonify, request
from flask_pluginengine import current_plugin
from pytz import timezone, utc
from werkzeug.exceptions import NotFound
from indico.core.db import db
from indico.modules.events.timetable.controllers import RHManageTimetableBase
from indico.modules.events.timetable.models.entries import TimetableEntry, TimetableEntryType
from MaKaC.webinterface.rh.base import RHProtected
@ -36,3 +44,70 @@ class RHImportData(RHProtected):
with plugin.plugin_context():
data = {'records': importer.import_data(query, size)}
return jsonify(data)
class RHEndTimeBase(RHManageTimetableBase):
"""Base class for the importer operations"""
normalize_url_spec = {
'locators': {
lambda self: self.event_new
},
'preserved_args': {
'importer_name'
}
}
@staticmethod
def _find_latest_end_dt(entries):
latest_dt = None
for entry in entries:
if latest_dt is None or entry.end_dt > latest_dt:
latest_dt = entry.end_dt
return latest_dt
def _format_date(self, date):
return date.astimezone(timezone(self.event_new.timezone)).strftime('%H:%M')
class RHDayEndTime(RHEndTimeBase):
"""Get the end_dt of the latest timetable entry or the event start_dt if no entry exist on that date"""
def _checkParams(self, params):
RHEndTimeBase._checkParams(self, params)
self.date = self.event_new.tzinfo.localize(datetime.strptime(request.args['selectedDay'], '%Y/%m/%d')).date()
def _process(self):
event_start_date = db.cast(TimetableEntry.start_dt.astimezone(self.event_new.tzinfo), db.Date)
entries = self.event_new.timetable_entries.filter(event_start_date == self.date)
latest_end_dt = self._find_latest_end_dt(entries)
if latest_end_dt is None:
event_start = self.event_new.start_dt
latest_end_dt = utc.localize(datetime.combine(self.date, event_start.time()))
return self._format_date(latest_end_dt)
class RHBlockEndTime(RHEndTimeBase):
"""Return the end_dt of the latest timetable entry inside the block or the block start_dt if it is empty"""
normalize_url_spec = {
'locators': {
lambda self: self.timetable_entry
},
'preserved_args': {
'importer_name'
}
}
def _checkParams(self, params):
RHEndTimeBase._checkParams(self, params)
self.date = timezone(self.event_new.timezone).localize(datetime.strptime(request.args['selectedDay'],
'%Y/%m/%d'))
self.timetable_entry = self.event_new.timetable_entries.filter_by(
type=TimetableEntryType.SESSION_BLOCK, id=request.view_args['entry_id']).first_or_404()
def _process(self):
entries = self.timetable_entry.children
latest_end_dt = self._find_latest_end_dt(entries)
if latest_end_dt is None:
latest_end_dt = self.timetable_entry.start_dt
return self._format_date(latest_end_dt)

View File

@ -18,9 +18,10 @@ from __future__ import unicode_literals
from indico.core import signals
from indico.core.plugins import IndicoPlugin, IndicoPluginBlueprint, plugin_url_rule_to_js, PluginCategory
from indico.modules.events.timetable.views import WPManageTimetable
from indico_importer import _
from indico_importer.controllers import RHGetImporters, RHImportData
from indico_importer.controllers import RHGetImporters, RHImportData, RHDayEndTime, RHBlockEndTime
class ImporterPlugin(IndicoPlugin):
@ -33,8 +34,8 @@ class ImporterPlugin(IndicoPlugin):
def init(self):
super(ImporterPlugin, self).init()
# self.inject_js('importer_js', WPConfModifScheduleGraphic)
# self.inject_css('importer_css', WPConfModifScheduleGraphic)
self.inject_js('importer_js', WPManageTimetable)
self.inject_css('importer_css', WPManageTimetable)
self.connect(signals.event.timetable_buttons, self.get_timetable_buttons)
self.importer_engines = {}
@ -59,3 +60,7 @@ class ImporterPlugin(IndicoPlugin):
blueprint = IndicoPluginBlueprint('importer', __name__)
blueprint.add_url_rule('/importers/<importer_name>/search', 'import_data', RHImportData, methods=('POST',))
blueprint.add_url_rule('/importers/', 'importers', RHGetImporters)
blueprint.add_url_rule('/importers/<importer_name>/event/<confId>/day-end-date', 'day_end_date', RHDayEndTime)
blueprint.add_url_rule('/importers/<importer_name>/event/<confId>/entry/<entry_id>/block-end-date', 'block_end_date',
RHBlockEndTime)

View File

@ -83,7 +83,7 @@
* Checks if a dictionary contains empty person data.
*/
isPersonEmpty: function(person) {
return person && (person.firstName || person.familyName);
return !person || (!person.firstName && !person.familyName);
},
/**
@ -96,6 +96,8 @@
* @param finalCallback Function executed after finishing all requests.
*/
multipleIndicoRequest: function(reqList, successCallback, errorCallback, finalCallback) {
return ImporterUtils._sendMultipleRequests(reqList, successCallback, errorCallback, finalCallback);
/*
if (reqList.length > 0) {
indicoRequest( reqList[0].method, reqList[0].args, function(result, error) {
if (result && successCallback) {
@ -110,7 +112,42 @@
} else if (finalCallback) {
finalCallback();
}
}
*/
},
_sendMultipleRequests: function(reqList, onSuccess, onError, onComplete) {
$.each(reqList, function(index, req) {
ImporterUtils._sendRequest(req.url, req.args, onSuccess, onError);
});
if (onComplete) {
onComplete();
}
},
_sendRequest: function(url, args, onSuccess, onError, onComplete) {
$.ajax({
url: url,
method: 'POST',
data: args,
success: function(data) {
if (data.success) {
onSuccess(data.entries[0]);
} else {
// FIXME where is the error message?
window.console.log(data);
onError("An error occured while adding the contribution.");
}
},
error: function(jqxhr, textStatus, errorThrown) {
onError(textStatus + ': ' + errorThrown);
},
complete: onComplete
});
if (onComplete) {
onComplete();
}
},
};
@ -418,25 +455,28 @@
self.info.set("startTime", this.destination.startDate.time.substr(0, 5));
hook.set(true);
} else {
var method;
var url;
if (this.destination.entryType == 'Day') {
method = 'schedule.event.getDayEndDate';
// FIXME build URL in a better way
url = '/importers/indico_importer/event/' + this.confId + '/day-end-date'
}
if (this.destination.entryType == 'Session') {
method = 'schedule.slot.getDayEndDate';
// FIXME build URL in a better way
url = '/importers/indico_importer/event/' + this.confId + '/entry/' +
this.destination.scheduleEntryId + '/block-end-date';
}
indicoRequest(method, {
'confId': this.confId,
'sessionId': this.destination.sessionId,
'slotId': this.destination.sessionSlotId,
'selectedDay': this.destination.startDate.date.replace(/-/g, '/')},
function(result, error) {
if (!error) {
self.info.set("startTime", result.substr(11, 5));
}
$.ajax({
url: url,
data: {
sessionId: this.destination.sessionId,
slotId: this.destination.sessionSlotId,
selectedDay: this.destination.startDate.date.replace(/-/g, '/')
},
success: function(data) {
self.info.set('startTime', data);
hook.set(true);
}
);
});
}
}
],
@ -492,6 +532,47 @@
}
},
_getUrl: function(legacy_method, eventId, day, destination) {
var params = "?" + $.param({'day': day});
if (legacy_method == 'schedule.event.addContribution') {
// FIXME build URL in a better way
return '/event/' + eventId + '/manage/timetable/add-contribution' + params;
}
if (legacy_method == 'schedule.slot.addContribution') {
params += '&' + $.param({'session_block_id': destination.sessionSlotId});
// FIXME build URL in a better way
return '/event/' + eventId + '/manage/timetable/add-contribution' + params;
}
if (legacy_method == 'contribution.addSubContribution') {
// FIXME build URL in a better way
return '/event/' + eventId + '/manage/contributions/' + destination.contributionId +
'/subcontributions/create';
}
// FIXME
alert('Unsupported method: ' + legacy_method);
},
_personLinkData: function(entry) {
var linkDataEntry = function(author, primary, speaker) {
return $.extend({
'authorType': primary ? 1 : 2,
'isSpeaker': speaker,
'isSubmitter': !speaker
}, author);
};
var linkData = [];
if (!ImporterUtils.isPersonEmpty(entry.primaryAuthor)) {
linkData.push(linkDataEntry(entry.primaryAuthor, true, false));
}
if (!ImporterUtils.isPersonEmpty(entry.secondaryAuthor)) {
linkData.push(linkDataEntry(entry.secondaryAuthor, false, false));
}
if (!ImporterUtils.isPersonEmpty(entry.speaker)) {
linkData.push(linkDataEntry(entry.speaker, false, true));
}
return linkData;
},
_getButtons: function() {
var self = this;
return [
@ -512,30 +593,40 @@
each(self.entries.getValues(), function(entry) {
entry = entry.getAll();
var timeStr = ImporterUtils.minutesToTime(time);
args.push({'method' : method,
'args' : {'conference' : self.confId,
'duration' : duration,
'title' : entry.title?entry.title:"Untitled",
'sessionId' : self.destination.sessionId,
'slotId' : self.destination.sessionSlotId,
'contribId' : self.destination.contributionId,
'startDate' : date + " " + timeStr,
'keywords' : [],
'authors':ImporterUtils.isPersonEmpty(entry.primaryAuthor)?[entry.primaryAuthor]:[],
'coauthors' : ImporterUtils.isPersonEmpty(entry.secondaryAuthor)?[entry.secondaryAuthor]:[],
'presenters' : ImporterUtils.isPersonEmpty(entry.speaker)?[entry.speaker]:[],
'roomInfo' : {},
'field_content': entry.summary,
'reportNumbers': entry.reportNumbers?
[{'system': ImporterUtils.reportNumberSystems[self.importer], 'number': entry.reportNumbers}]:[],
'materials': entry.materials}
var params = {
'csrf_token': $('#csrf-token').attr('content'),
'title': entry.title ? entry.title : "Untitled",
'description': entry.summary,
'duration': [duration, 'minutes'],
'references': '[]'
}
if (self.destination.entryType == "Contribution") {
$.extend(params, {
'speakers': Json.write(self._personLinkData(entry))
});
} else {
$.extend(params, {
'time': timeStr,
//'keywords' : [],
'person_link_data': Json.write(self._personLinkData(entry)),
//'roomInfo' : {},
'location_data': '{"address": "", "inheriting": true}',
'type': '__None',
//'reportNumbers': entry.reportNumbers?
// [{'system': ImporterUtils.reportNumberSystems[self.importer], 'number': entry.reportNumbers}]:[],
'materials': Json.write(entry.materials)
});
}
args.push({
'url': self._getUrl(method, self.confId, date, self.destination),
'args': params
});
time += duration;
});
var successCallback = function(result) {
if (exists(result.slotEntry) && self.timetable.contextInfo.id == result.slotEntry.id) {
self.timetable._updateEntry(result, result.id);
} else{
} else {
var timetable = self.timetable.parentTimetable?self.timetable.parentTimetable:self.timetable;
timetable._updateEntry(result, result.id);
}
@ -832,13 +923,13 @@
recordDiv.append(Html.div({}, Html.em({}, $t.gettext("Meeting")), ": ", record.get("meetingName")));
}
// Speaker, primary and secondary authors are stored in dictionaries. Their property have to be checked.
if (ImporterUtils.isPersonEmpty(record.get("primaryAuthor"))) {
if (!ImporterUtils.isPersonEmpty(record.get("primaryAuthor"))) {
recordDiv.append(Html.div({}, Html.em({}, $t.gettext("Primary author")), ": ", this._getPersonString(record.get("primaryAuthor"))));
}
if (ImporterUtils.isPersonEmpty(record.get("secondaryAuthor"))) {
if (!ImporterUtils.isPersonEmpty(record.get("secondaryAuthor"))) {
recordDiv.append(Html.div({}, Html.em({}, $t.gettext("Secondary author")), ": ", this._getPersonString(record.get("secondaryAuthor"))));
}
if (ImporterUtils.isPersonEmpty(record.get("speaker"))) {
if (!ImporterUtils.isPersonEmpty(record.get("speaker"))) {
recordDiv.append(Html.div({}, Html.em({}, $t.gettext("Speaker")), ": ", this._getPersonString(record.get("speaker"))));
}
if (record.get("summary")) {
@ -1356,7 +1447,7 @@
$(function() {
$('#timetableDiv').on('click', '.js-create-importer-dialog', function() {
$('#timetable').on('click', '.js-create-importer-dialog', function() {
var timetable = $(this).data('timetable');
new ImportDialog(timetable);
});