diff options
| author | User Erdgeist <erdgeist@content.events.ccc.de> | 2019-10-30 14:24:31 +0000 |
|---|---|---|
| committer | User Erdgeist <erdgeist@content.events.ccc.de> | 2019-10-30 14:24:31 +0000 |
| commit | cd9e07341c2eebba1ed6980acdd07acc6ab9c9f4 (patch) | |
| tree | ffcff44a758dfe510b4e7be3fbb3839a69193abc | |
| parent | 8bcbcea5580818661eebcd17190780feb6e5bb86 (diff) | |
Add export to RT tool
| -rwxr-xr-x | export.py | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/export.py b/export.py new file mode 100755 index 0000000..97ad669 --- /dev/null +++ b/export.py | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | #!venv/bin/python | ||
| 2 | |||
| 3 | from flask import Flask, render_template, jsonify, request | ||
| 4 | from flask_sqlalchemy import SQLAlchemy | ||
| 5 | from lxml import etree | ||
| 6 | from argparse import ArgumentParser | ||
| 7 | import requests | ||
| 8 | import json | ||
| 9 | import sys | ||
| 10 | |||
| 11 | dryrun=False | ||
| 12 | |||
| 13 | parser = ArgumentParser(description="C3 rating helper") | ||
| 14 | parser.add_argument("-d", action="store_true", dest="dryrun", default=False, help="Don't actually execute anything on frab or rt, just show what would have been done") | ||
| 15 | args = parser.parse_args() | ||
| 16 | |||
| 17 | if args.dryrun: | ||
| 18 | dryrun=True | ||
| 19 | |||
| 20 | with open(args.config, mode="r", encoding="utf-8") as json_file: | ||
| 21 | cfg = json.load(json_file) | ||
| 22 | |||
| 23 | app = Flask(__name__) | ||
| 24 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + cfg['frab-conference'] + '-' + cfg['track'] + '.db' | ||
| 25 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | ||
| 26 | app.config['SECRET_KEY'] = 'Silence is golden. Gerd Eist.' | ||
| 27 | app.jinja_env.trim_blocks = True | ||
| 28 | app.jinja_env.lstrip_blocks = True | ||
| 29 | |||
| 30 | db = SQLAlchemy(app) | ||
| 31 | |||
| 32 | config['rt-rest-url'] = cfg['rt-url'] + 'REST/1.0/' | ||
| 33 | config['frab-conf-url'] = config['frab-url'] + config['frab-conference'] | ||
| 34 | |||
| 35 | class Event(db.Model): | ||
| 36 | """An event as dumped from frab""" | ||
| 37 | frab_id = db.Column(db.Integer, primary_key=True) | ||
| 38 | title = db.Column(db.String(1024)) | ||
| 39 | subtitle = db.Column(db.String(1024)) | ||
| 40 | abstract = db.Column(db.Text()) | ||
| 41 | description = db.Column(db.Text()) | ||
| 42 | state = db.Column(db.String(64)) | ||
| 43 | event_type = db.Column(db.String(64)) | ||
| 44 | speakers = db.Column(db.String(1024)) | ||
| 45 | coordinator = db.Column(db.String(1024)) | ||
| 46 | notes = db.Column(db.Text()) | ||
| 47 | |||
| 48 | class EventRating(db.Model): | ||
| 49 | """A rating as given by a logged in user""" | ||
| 50 | id = db.Column(db.Integer, primary_key=True) | ||
| 51 | submitter = db.Column(db.String(1024)) | ||
| 52 | event_id = db.Column(db.Integer, db.ForeignKey('event.frab_id')) | ||
| 53 | event = db.relationship('Event', backref=db.backref('ratings', lazy='dynamic')) | ||
| 54 | comment = db.Column(db.Text()) | ||
| 55 | rating_dict = db.Column(db.String(1024), server_default="{}") | ||
| 56 | |||
| 57 | def add_coordinator(sess, person, event): | ||
| 58 | edit_person_page = sess.get(config['frab-conf-url'] + '/events/' + event + '/edit_people') | ||
| 59 | tree = etree.HTML(edit_person_page.text) | ||
| 60 | for option in tree.xpath('//option[@selected]'): | ||
| 61 | if option.text.lower() == 'coordinator': | ||
| 62 | print ('Not patching: ' + person + ' on event ' + event + ', coordinator found') | ||
| 63 | return | ||
| 64 | # print (option.text) | ||
| 65 | print ('Patching: ' + person + ' on event ' + event) | ||
| 66 | |||
| 67 | if dryrun: | ||
| 68 | return | ||
| 69 | |||
| 70 | add_person_data = dict() | ||
| 71 | add_person_data['utf8'] = '✓' | ||
| 72 | add_person_data['commit'] = 'Update event' | ||
| 73 | add_person_data['_method'] = 'PATCH' | ||
| 74 | add_person_data['filter'] = '' | ||
| 75 | add_person_data['authenticity_token'] = tree.xpath("//meta[@name='csrf-token']")[0].get("content") | ||
| 76 | add_person_data['event[event_people_attributes][1510531378][person_id]'] = person | ||
| 77 | add_person_data['event[event_people_attributes][1510531378][event_role]'] = 'coordinator' | ||
| 78 | add_person_data['event[event_people_attributes][1510531378][role_state]'] = '' | ||
| 79 | add_person_data['event[event_people_attributes][1510531378][_destroy]'] = 'false' | ||
| 80 | response = sess.post(config['frab-conf-url'] + '/events/' + event, add_person_data) | ||
| 81 | # print (response.text) | ||
| 82 | |||
| 83 | def add_ticket(sess, rt_sess, event, person): | ||
| 84 | event_page = sess.get(config['frab-conf-url'] + '/events/' + event) | ||
| 85 | tree = etree.HTML(event_page.text) | ||
| 86 | click = '' | ||
| 87 | for button in tree.xpath('//a[@class="btn primary"]/@href'): | ||
| 88 | if '/tickets/' in button: | ||
| 89 | click = button | ||
| 90 | break | ||
| 91 | if not click: | ||
| 92 | print ('No add ticket link found, event already has a ticket?') | ||
| 93 | return | ||
| 94 | print ('Using add ticket link: ' + click) | ||
| 95 | |||
| 96 | if dryrun: | ||
| 97 | return | ||
| 98 | |||
| 99 | ticket_data = dict() | ||
| 100 | ticket_data['authenticity_token'] = tree.xpath("//meta[@name='csrf-token']")[0].get("content") | ||
| 101 | ticket_data['_method'] = 'POST' | ||
| 102 | response = sess.post(cfg['frab-url'] + click, ticket_data) | ||
| 103 | tree = etree.HTML(response.text) | ||
| 104 | ticket_id = '' | ||
| 105 | for link in tree.xpath('//a/@href'): | ||
| 106 | if '/Ticket/Display.html?' in link: | ||
| 107 | ticket_id = link.split('=')[1] | ||
| 108 | print ('Found new ticket, #'+ticket_id) | ||
| 109 | 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']}) | ||
| 110 | print (response.text) | ||
| 111 | if not ticket_id: | ||
| 112 | print ('Failed to add ticket to event ' + event) | ||
| 113 | |||
| 114 | def set_state(sess, event, state): | ||
| 115 | event_page = sess.get(config['frab-conf-url'] + '/events/' + event) | ||
| 116 | tree = etree.HTML(event_page.text) | ||
| 117 | click = '' | ||
| 118 | for button in tree.xpath('//a[starts-with(@class,"btn")]/@href'): | ||
| 119 | if '?transition=' + state in button: | ||
| 120 | click = button | ||
| 121 | break | ||
| 122 | if not click: | ||
| 123 | print ('No ' + state + ' button found. State already set?') | ||
| 124 | return | ||
| 125 | print ('Using set state link: ' + click) | ||
| 126 | if dryrun: | ||
| 127 | return | ||
| 128 | set_state_data = dict() | ||
| 129 | set_state_data['authenticity_token'] = tree.xpath("//meta[@name='csrf-token']")[0].get("content") | ||
| 130 | set_state_data['_method'] = 'PUT' | ||
| 131 | response = sess.post(cgf['frab-url'] + click, set_state_data) | ||
| 132 | |||
| 133 | def put_talks(): | ||
| 134 | sess = requests.Session() | ||
| 135 | new_session_page = sess.get(cfg['frab-url']) | ||
| 136 | tree = etree.HTML(new_session_page.text) | ||
| 137 | login_data = dict() | ||
| 138 | login_data['user[email]'] = cfg['frab-user'] | ||
| 139 | login_data['user[password]'] = cfg['frab-password'] | ||
| 140 | login_data['user[remember_me]'] = 1 | ||
| 141 | login_data['authenticity_token'] = tree.xpath("//meta[@name='csrf-token']")[0].get("content") | ||
| 142 | sess.post(cfg['frab-url'] + 'users/sign_in?conference_acronym=' + cfg['frab-conference'] + '&locale=en', login_data) | ||
| 143 | |||
| 144 | rt_sess = requests.Session() | ||
| 145 | rt_sess.post(cfg['rt-url']+'index.html', {"user": cfg['rt-user'], "pass": cfg['rt-password'] }) | ||
| 146 | |||
| 147 | for event in Event.query.all(): | ||
| 148 | if event.coordinator: | ||
| 149 | if event.coordinator in person_map: | ||
| 150 | print (str(event.frab_id) + ': ' + event.coordinator + '(' + cfg.get('frab-person-map')[event.coordinator]+')') | ||
| 151 | add_coordinator(sess, cfg.get('frab-person-map')[event.coordinator], str(event.frab_id)) | ||
| 152 | add_ticket(sess, rt_sess, str(event.frab_id), cfg.get('rt-person-map')[event.coordinator]) | ||
| 153 | else: | ||
| 154 | print ('Unknown coordinator '+event.coordinator+' for event '+str(event.frab_id)) | ||
| 155 | if event.state in [ 'accepted', 'rejected' ]: | ||
| 156 | set_state(sess, str(event.frab_id), 'accept' if event.state == 'accepted' else 'reject') | ||
| 157 | else: | ||
| 158 | print ('Unknown state ' + event.state + ' for event ' + str(event.frab_id)) | ||
| 159 | |||
| 160 | if __name__ == "__main__": | ||
| 161 | db.create_all() | ||
| 162 | put_talks() | ||
