#!venv/bin/python from flask import Flask, render_template, jsonify, request from flask_sqlalchemy import SQLAlchemy from lxml import etree from argparse import ArgumentParser import requests import json import sys dryrun=False parser = ArgumentParser(description="C3 rating helper") parser.add_argument("-d", action="store_true", dest="dryrun", default=False, help="Don't actually execute anything on pretalx or rt, just show what would have been done") args = parser.parse_args() if args.dryrun: dryrun=True with open(args.config, mode="r", encoding="utf-8") as json_file: cfg = json.load(json_file) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + cfg['pretalx-conference'] + '-' + cfg['track'] + '.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SECRET_KEY'] = 'Silence is golden. Gerd Eist.' app.jinja_env.trim_blocks = True app.jinja_env.lstrip_blocks = True db = SQLAlchemy(app) config['rt-rest-url'] = cfg['rt-url'] + 'REST/1.0/' config['pretalx-conf-url'] = config['pretalx-url'] + config['pretalx-conference'] class Event(db.Model): """An event as dumped from pretalx""" pretalx_id = db.Column(db.String(16), primary_key=True) title = db.Column(db.String(1024)) abstract = db.Column(db.Text()) description = db.Column(db.Text()) state = db.Column(db.String(64)) event_type = db.Column(db.String(64)) speakers = db.Column(db.String(1024)) coordinator = db.Column(db.String(1024)) notes = db.Column(db.Text()) class EventRating(db.Model): """A rating as given by a logged in user""" id = db.Column(db.Integer, primary_key=True) submitter = db.Column(db.String(1024)) event_id = db.Column(db.Integer, db.ForeignKey('event.pretalx_id')) event = db.relationship('Event', backref=db.backref('ratings', lazy='dynamic')) comment = db.Column(db.Text()) rating_dict = db.Column(db.String(1024), server_default="{}") def add_coordinator(sess, person, event): edit_person_page = sess.get(config['pretalx-conf-url'] + '/events/' + event + '/edit_people') tree = etree.HTML(edit_person_page.text) for option in tree.xpath('//option[@selected]'): if option.text.lower() == 'coordinator': print ('Not patching: ' + person + ' on event ' + event + ', coordinator found') return # print (option.text) print ('Patching: ' + person + ' on event ' + event) if dryrun: return add_person_data = dict() add_person_data['utf8'] = '✓' add_person_data['commit'] = 'Update event' add_person_data['_method'] = 'PATCH' add_person_data['filter'] = '' add_person_data['authenticity_token'] = tree.xpath("//meta[@name='csrf-token']")[0].get("content") add_person_data['event[event_people_attributes][1510531378][person_id]'] = person add_person_data['event[event_people_attributes][1510531378][event_role]'] = 'coordinator' add_person_data['event[event_people_attributes][1510531378][role_state]'] = '' add_person_data['event[event_people_attributes][1510531378][_destroy]'] = 'false' response = sess.post(config['frab-conf-url'] + '/events/' + event, add_person_data) # print (response.text) def add_ticket(sess, rt_sess, event, person): event_page = sess.get(config['frab-conf-url'] + '/events/' + event) tree = etree.HTML(event_page.text) click = '' for button in tree.xpath('//a[@class="btn primary"]/@href'): if '/tickets/' in button: click = button break if not click: print ('No add ticket link found, event already has a ticket?') return print ('Using add ticket link: ' + click) if dryrun: return ticket_data = dict() ticket_data['authenticity_token'] = tree.xpath("//meta[@name='csrf-token']")[0].get("content") ticket_data['_method'] = 'POST' response = sess.post(cfg['frab-url'] + click, ticket_data) tree = etree.HTML(response.text) ticket_id = '' for link in tree.xpath('//a/@href'): if '/Ticket/Display.html?' in link: ticket_id = link.split('=')[1] print ('Found new ticket, #'+ticket_id) response = rt_sess.post(config['rt-rest-url'] + 'ticket/' + ticket_id + '/edit', { "content": "id: ticket/"+ticket_id + '\nOwner: ' + person + '\n' }, headers={ 'referer': config['rt-rest-url']}) print (response.text) if not ticket_id: print ('Failed to add ticket to event ' + event) def set_state(sess, event, state): event_page = sess.get(config['frab-conf-url'] + '/events/' + event) tree = etree.HTML(event_page.text) click = '' for button in tree.xpath('//a[starts-with(@class,"btn")]/@href'): if '?transition=' + state in button: click = button break if not click: print ('No ' + state + ' button found. State already set?') return print ('Using set state link: ' + click) if dryrun: return set_state_data = dict() set_state_data['authenticity_token'] = tree.xpath("//meta[@name='csrf-token']")[0].get("content") set_state_data['_method'] = 'PUT' response = sess.post(cgf['frab-url'] + click, set_state_data) def put_talks(): sess = requests.Session() new_session_page = sess.get(cfg['frab-url']) tree = etree.HTML(new_session_page.text) login_data = dict() login_data['user[email]'] = cfg['frab-user'] login_data['user[password]'] = cfg['frab-password'] login_data['user[remember_me]'] = 1 login_data['authenticity_token'] = tree.xpath("//meta[@name='csrf-token']")[0].get("content") sess.post(cfg['frab-url'] + 'users/sign_in?conference_acronym=' + cfg['frab-conference'] + '&locale=en', login_data) rt_sess = requests.Session() rt_sess.post(cfg['rt-url']+'index.html', {"user": cfg['rt-user'], "pass": cfg['rt-password'] }) for event in Event.query.all(): if event.coordinator: if event.coordinator in person_map: print (str(event.frab_id) + ': ' + event.coordinator + '(' + cfg.get('frab-person-map')[event.coordinator]+')') add_coordinator(sess, cfg.get('frab-person-map')[event.coordinator], str(event.frab_id)) add_ticket(sess, rt_sess, str(event.frab_id), cfg.get('rt-person-map')[event.coordinator]) else: print ('Unknown coordinator '+event.coordinator+' for event '+str(event.frab_id)) if event.state in [ 'accepted', 'rejected' ]: set_state(sess, str(event.frab_id), 'accept' if event.state == 'accepted' else 'reject') else: print ('Unknown state ' + event.state + ' for event ' + str(event.frab_id)) if __name__ == "__main__": db.create_all() put_talks()