|
| 1 | +# -*-*- encoding: utf-8 -*-*- |
| 2 | + |
| 3 | +import re |
| 4 | +import sys |
| 5 | +from bs4 import BeautifulSoup |
| 6 | +import json |
| 7 | +import datetime |
| 8 | +import uuid |
| 9 | +import hashlib |
| 10 | +import urllib2 |
| 11 | + |
| 12 | +from flask.ext.wtf import TextField, PasswordField, Required, URL, ValidationError |
| 13 | + |
| 14 | +from labmanager.forms import AddForm, RetrospectiveForm, GenericPermissionForm |
| 15 | +from labmanager.rlms import register, Laboratory |
| 16 | +from labmanager.rlms.base import BaseRLMS, BaseFormCreator, Capabilities, Versions |
| 17 | + |
| 18 | +def get_module(version): |
| 19 | + """get_module(version) -> proper module for that version |
| 20 | +
|
| 21 | + Right now, a single version is supported, so this module itself will be returned. |
| 22 | + When compatibility is required, we may change this and import different modules. |
| 23 | + """ |
| 24 | + # TODO: check version |
| 25 | + return sys.modules[__name__] |
| 26 | + |
| 27 | +class PhETAddForm(AddForm): |
| 28 | + |
| 29 | + def __init__(self, add_or_edit, *args, **kwargs): |
| 30 | + super(PhETAddForm, self).__init__(*args, **kwargs) |
| 31 | + self.add_or_edit = add_or_edit |
| 32 | + |
| 33 | + @staticmethod |
| 34 | + def process_configuration(old_configuration, new_configuration): |
| 35 | + return new_configuration |
| 36 | + |
| 37 | +class PhETPermissionForm(RetrospectiveForm): |
| 38 | + pass |
| 39 | + |
| 40 | +class PhETLmsPermissionForm(PhETPermissionForm, GenericPermissionForm): |
| 41 | + pass |
| 42 | + |
| 43 | +class PhETFormCreator(BaseFormCreator): |
| 44 | + |
| 45 | + def get_add_form(self): |
| 46 | + return PhETAddForm |
| 47 | + |
| 48 | + def get_permission_form(self): |
| 49 | + return PhETPermissionForm |
| 50 | + |
| 51 | + def get_lms_permission_form(self): |
| 52 | + return PhETLmsPermissionForm |
| 53 | + |
| 54 | +FORM_CREATOR = PhETFormCreator() |
| 55 | + |
| 56 | +class RLMS(BaseRLMS): |
| 57 | + |
| 58 | + def __init__(self, configuration): |
| 59 | + self.configuration = json.loads(configuration or '{}') |
| 60 | + |
| 61 | + def get_version(self): |
| 62 | + return Versions.VERSION_1 |
| 63 | + |
| 64 | + def get_capabilities(self): |
| 65 | + return [ Capabilities.WIDGET ] |
| 66 | + |
| 67 | + def test(self): |
| 68 | + json.loads(self.configuration) |
| 69 | + # TODO |
| 70 | + return None |
| 71 | + |
| 72 | + def get_laboratories(self): |
| 73 | + index_html = urllib2.urlopen("https://phet.colorado.edu/en/simulations/index").read() |
| 74 | + soup = BeautifulSoup(index_html) |
| 75 | + |
| 76 | + laboratories = [] |
| 77 | + |
| 78 | + for h2 in soup.find_all("h2"): |
| 79 | + parent_identifier = h2.parent.get('id') |
| 80 | + # Just checking that the format has not changed |
| 81 | + if parent_identifier and len(parent_identifier) == 1 and parent_identifier in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': |
| 82 | + for link in h2.parent.find_all("a"): |
| 83 | + link_href = 'https://phet.colorado.edu%s' % link.get('href') |
| 84 | + name = link.find("span").text |
| 85 | + laboratories.append(Laboratory(name = name, laboratory_id = link_href)) |
| 86 | + |
| 87 | + return laboratories |
| 88 | + |
| 89 | + def reserve(self, laboratory_id, username, institution, general_configuration_str, particular_configurations, request_payload, user_properties, *args, **kwargs): |
| 90 | + |
| 91 | + laboratory_html = urllib2.urlopen(laboratory_id).read() |
| 92 | + soup = BeautifulSoup(laboratory_html) |
| 93 | + |
| 94 | + url = "" |
| 95 | + |
| 96 | + # If there's a "Run in HTML5" button |
| 97 | + html5_url = soup.find("a", class_="sim-button", text=re.compile("HTML5")) |
| 98 | + |
| 99 | + if html5_url: |
| 100 | + # Then that's the URL |
| 101 | + url = html5_url.get("href") |
| 102 | + else: |
| 103 | + # Otherwise, if there is a embeddable-text |
| 104 | + embed_text = soup.find(id="embeddable-text").text |
| 105 | + |
| 106 | + # Then, check what's inside: |
| 107 | + embed_soup = BeautifulSoup(embed_text) |
| 108 | + |
| 109 | + # If it's an iframe, the src is the URL |
| 110 | + iframe_tag = embed_soup.find("iframe") |
| 111 | + if iframe_tag: |
| 112 | + url = iframe_tag.get("src") |
| 113 | + else: |
| 114 | + # Otherwise, the link is the URL |
| 115 | + a_tag = embed_soup.find("a") |
| 116 | + url = a_tag.get("href") |
| 117 | + |
| 118 | + return { |
| 119 | + 'reservation_id' : url, |
| 120 | + 'load_url' : url |
| 121 | + } |
| 122 | + |
| 123 | + def load_widget(self, reservation_id, widget_name): |
| 124 | + return { |
| 125 | + 'url' : reservation_id |
| 126 | + } |
| 127 | + |
| 128 | + def list_widgets(self, laboratory_id): |
| 129 | + default_widget = dict( name = 'default', description = 'Default widget' ) |
| 130 | + return [ default_widget ] |
| 131 | + |
| 132 | +register("PhET", ['1.0'], __name__) |
| 133 | + |
| 134 | +def main(): |
| 135 | + rlms = RLMS("{}") |
| 136 | + laboratories = rlms.get_laboratories() |
| 137 | + print len(laboratories) |
| 138 | + print |
| 139 | + print laboratories[:10] |
| 140 | + print |
| 141 | + for lab in laboratories[:5]: |
| 142 | + print rlms.reserve(lab.laboratory_id, 'tester', 'foo', '', '', '', '') |
| 143 | + |
| 144 | + |
| 145 | +if __name__ == '__main__': |
| 146 | + main() |
0 commit comments