def post(self): """ Handles plugin editing and activation. """ form = self.form try: if form.action == 'check_dependencies': self.plugin_manager.check_all_plugins_dependencies() else: plugin_id = int(form.id) p = Plugin.get(plugin_id) current_user = User.get(self.session['user']['id']) if form.action == 'edit': state = 'yes' if 'state' in form and form.state == 'on' else 'no' try: form.name = p.name if p.activated == 'notfound': raise ImmediateFeedback('general', 'plugin_activate_not_found') p.set(activated=state) if p.activated == 'yes': if self.plugin_manager.instantiate_plugin(self.app, p): add_feedback('general', 'plugin_activated') else: raise ImmediateFeedback('general', 'plugin_activation_error') else: add_feedback('general', 'plugin_disabled') except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') elif form.action == 'configure': try: for param in p.params_access_rights: param.channel_contributor_read = form.get(param.name + '-cc-r') == 'on' param.channel_contributor_write = form.get(param.name + '-cc-w') == 'on' param.channel_administrator_read = form.get(param.name + '-ca-r') == 'on' param.channel_administrator_write = form.get(param.name + '-ca-w') == 'on' param.administrator_write = form.get(param.name + '-a-r') == 'on' param.administrator_write = form.get(param.name + '-a-w') == 'on' p.cache_activated_default = form.get('cache-activated') == 'on' if 'cache-validity' in form: p.cache_validity_default = int(form['cache-validity']) p.keep_noncomplying_capsules_default = form.get('keep-capsules') == 'on' p.drop_silently_non_complying_slides_default = form.get('drop-silently') == 'on' form.name = p.name add_feedback('general', 'plugin_configured') except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') elif form.action == 'delete': if p.channels.count() > 0 and 'confirm-delete' not in form: raise ImmediateFeedback(form.action, 'plugin_has_channels', {'plugin': p.to_dictionary(['id', 'name', 'channels_number', 'screens_number']), 'channels': [(c.id, c.name, c.enabled) for c in p.channels]}) plugin_name = p.name form.name = plugin_name p.destroySelf() logger.info('The plugin %s has been deleted by %s', plugin_name, current_user.log_name) add_feedback('general', 'plugin_deleted') except ImmediateFeedback: pass store_form(form) return self.render_page()
def post(self): """ Handles building creation, editing and deletion. """ current_user = User.get(self.session['user']['id']) form = self.form try: if form.action == 'delete': if not current_user.super_admin: raise flask.redirect('',code=403) try: id = int(form.id) except ValueError: logger.warning('user %s tries to delete a building with invalid id (id = %s)', current_user.log_name, str(form.id)) raise ImmediateFeedback(form.action, 'invalid_id') try: screens = Screen.selectBy(building=id) if screens.count() > 0: logger.warning('user %s tries to delete a building with screens still present in this building (id = %s)', current_user.log_name, str(id)) raise ImmediateFeedback(form.action, 'delete_building_but_screens_present', [(s.id, s.name) for s in screens]) Building.delete(id) logger.info("building %s has been deleted by user %s", str(id), current_user.log_name) except SQLObjectNotFound as e: logger.warning("user %s tries to delete a building with an id that doesn't exist (id = %s)", current_user.log_name, str(form.id)) raise ImmediateFeedback(form.action, 'no_id_matching') else: name = form.name.strip() if name == "": raise ImmediateFeedback(form.action, 'empty_name') if len(form.name) > Building.sqlmeta.columns['name'].length: raise ImmediateFeedback(form.action, 'too_long_name') if form.action == 'create': try: Building(name=form.name, city=form.city) logger.info("building %s has been created by user %s", form.name, current_user.log_name) except DuplicateEntryError: logger.warning("user %s tries to create a building with a name that already exists (name = %s)", current_user.log_name, form.name) raise ImmediateFeedback(form.action, 'name_already_exists') elif form.action == 'edit': try: id = int(form.id) except ValueError: logger.warning('user %s tries to edit a building with invalid id (id = %s)', current_user.log_name, str(form.id)) raise ImmediateFeedback(form.action, 'invalid_building_id') try: building = Building.get(id) except SQLObjectNotFound as e: logger.warning("user %s tries to edit a building with an id that doesn't exist (id = %s)", current_user.log_name, str(form.id)) raise ImmediateFeedback(form.action, 'no_id_matching') try: building.name = form.name building.city = form.city except DuplicateEntryError: logger.warning("user %s tries to edit the building %s with a name already present (name = %d)", current_user.log_name, str(form.id), form.name) raise ImmediateFeedback(form.action, 'name_already_exists') logger.info("building %s has been edited by user %s (new name = %s)", str(id), current_user.log_name, form.name) add_feedback(form.action, 'ok') except ImmediateFeedback: store_form(form) return self.render_page()
def post(self, channel_id): channel = Channel.get(int(channel_id)) form = self.form try: if form.action == 'add-channel-to-bundles': bundles_diff = json.loads(form.pop('diff', '{}')) for bundle_id, part_of in bundles_diff.items(): bundle = ChannelBundle.get(int(bundle_id)) if part_of: try: bundle.add_channel(channel) except ValueError: raise ImmediateFeedback(form.action, 'bundle_cycle', bundle.name) else: bundle.remove_channel(channel) add_feedback(form.action, 'ok') except ImmediateFeedback: pass form.was_bundle = type( channel ) == ChannelBundle # Hack to display the bundles tab instead form.data_edit = json.dumps([b.id for b in channel.bundles]) form.channel_id = channel_id form.name = channel.name store_form(form) resp.seeother('/channels')
def common_feedback(self): web.ctx.session = self.ictv_app.session l = get_feedbacks() val = "test" assert_false( l.has(type="TESTINGFEEDBACK", message="This is a test feedback from the unit test")) add_feedback(type="TESTINGFEEDBACK", message="This is a test feedback from the unit test", value=val) l = get_next_feedbacks() assert_true( l.has(type="TESTINGFEEDBACK", message="This is a test feedback from the unit test")) assert_is_not_none( l.feedback_value( type="TESTINGFEEDBACK", message="This is a test feedback from the unit test")) assert_is_none( l.feedback_value( type="TESTINGFEEDBACK2", message="This is a test feedback from the unit test again")) assert_is_not_none(l.feedback_value(type=None, message=None)) assert_true(l.has_type(type="TESTINGFEEDBACK")) i = ImmediateFeedback( type="TESTINGFEEDBACK", message="This is a test feedback from the unit test", value=val)
def post(self, secret): user = User.selectBy(reset_secret=secret).getOne(None) form = self.form try: if form.get('password1') != form.get('password2'): raise ImmediateFeedback('reset', 'passwords_do_not_match') password = form.password1.strip() if len(password) <= 3: raise ImmediateFeedback('reset', 'password_insufficient') user.password = hash_password(form.password1) user.reset_secret = utils.generate_secret() # Make this token one time use logger.info('User %s has reset its password from IP %s', user.log_name, flask.g.ip) except ImmediateFeedback: return self.standalone_renderer.reset(user=user) add_feedback('reset', 'ok') resp.seeother(flask.url_for("LoginPage"))
def post(self, channel_id, channel): """ Handles channel creation, editing, deletion, configuration and user permissions. """ form = self.form current_user = User.get(self.session['user']['id']) try: if form.action == 'reset-config': if form.all == "true": for param_id, param_attrs in channel.plugin.channels_params.items( ): read, write = channel.get_access_rights_for( param_id, current_user) if read and write: channel.plugin_config.pop(param_id, None) # Force SQLObject update channel.plugin_config = channel.plugin_config else: param_id = form["reset-param-id"] if param_id not in channel.plugin.channels_params.keys(): raise ImmediateFeedback(form.action, "invalid_param_id") read, write = channel.get_access_rights_for( param_id, current_user) if read and write: channel.plugin_config.pop(param_id, None) else: raise self.forbidden() # Force SQLObject update channel.plugin_config = channel.plugin_config channel.syncUpdate() logger.info('params of channel ' + channel.name + ' reset by ' + current_user.log_name) elif form.action == 'reset-cache-config': if not current_user.super_admin: raise self.forbidden() form.name = channel.name channel.cache_activated = None channel.cache_validity = None add_feedback('general', 'channel_cache_reset') logger.info( 'the cache configuration of channel %s has been reset by user %s', channel.name, current_user.log_name) elif form.action == 'reset-filtering-config': if not current_user.super_admin: raise self.forbidden() form.name = channel.name channel.keep_noncomplying_capsules = None add_feedback('general', 'channel_filtering_reset') logger.info( 'the capsule filtering configuration of channel %s has been reset by user %s', channel.name, current_user.log_name) add_feedback('general', 'channel_edited') add_feedback(form.action, 'ok') form.name = channel.name except ImmediateFeedback: if channel is not None and channel.enabled: form.enabled = 'on' store_form(form) resp.seeother('/channels/config/%d' % channel.id)
def post(self): if 'user' in self.session: resp.seeother('/') form = self.form try: user = User.selectBy(email=form.email, password=hash_password(form.password)).getOne(None) if not user: raise ImmediateFeedback('login', 'invalid_credentials') self.session['user'] = user.to_dictionary(['id', 'fullname', 'username', 'email']) except ImmediateFeedback: store_form(form) return self.render_page() resp.seeother('/')
def post(self, screen_id): def wrong_channel(channel, subscribe, user): """ returns True if the the user wants to subscribe to the channel while its plugin is not activated or if the user tries to subscribe to the channel without being in its authorized subscribers""" return subscribe and (type(channel) is PluginChannel and channel.plugin.activated != "yes" or (subscribe and not channel.can_subscribe(user))) form = self.form try: screen = Screen.get(screen_id) u = User.get(self.session['user']['id']) # Forbid if not admin or does not own this screen if not (UserPermissions.administrator in u.highest_permission_level or screen in u.screens): logger.warning('user %s tried change subscriptions of screen %d without having the rights to do this', u.log_name, screen.id) resp.forbidden() diff = json.loads(form.diff) if diff == {}: logger.info('user %s submitted empty diff for subscriptions of screen %s', u.log_name, screen.name) raise ImmediateFeedback("subscription", 'nothing_changed') # Do the subscription/unsubscription for every channel in the diff subscribed = [] unsubscribed = [] try: changes = [(Channel.get(channel_id), subscribe) for channel_id, subscribe in diff.items()] except SQLObjectNotFound: logger.warning('user %s tried to subscribe/unsubscribe screen %d to a channel which does not exist', u.log_name, screen.id) resp.forbidden() # if somebody tries to subscribe to a channel with a disabled plugin wrong_channels = [(channel, subscribe) for channel, subscribe in changes if wrong_channel(channel, subscribe, u)] if wrong_channels: channel, subscribe = wrong_channels[0] if channel.plugin.activated != "yes": logger.warning('user %s tried to %s screen %d to channel %d with disabled plugin', u.log_name, 'subscribe' if subscribe else "unsubscribe", screen.id, channel.id) raise ImmediateFeedback("subscription", "disabled_plugin") else: logger.warning('user %s tried to subscribe screen %d to channel %d without having the right to do this', u.log_name, screen.id, channel.id) resp.forbidden() for channel, subscribe in changes: if subscribe: screen.subscribe_to(u, channel) subscribed.append(str(channel.id)) else: screen.unsubscribe_from(u, channel) unsubscribed.append(str(channel.id)) if subscribed and unsubscribed: message = "user %s has subscribed screen %d to channel(s) %s and unsubscribed from channel(s) %s" % \ (u.log_name, screen.id, ', '.join(subscribed), ', '.join(unsubscribed)) else: message = "user %s has %s screen %d to channel(s) %s" % \ (u.log_name, "subscribed" if subscribed else "unsubscribed", screen.id, ', '.join(subscribed if subscribed else unsubscribed)) logger.info(message) add_feedback("subscription", 'ok') except SQLObjectNotFound: resp.notfound() except ImmediateFeedback: pass store_form(form) resp.seeother("/screens/%s/subscriptions" % screen.id)
def post(self, channel_id): form = self.form u = User.get(self.session['user']['id']) subscribed = [] unsubscribed = [] if form.diff == 'diff': raise ImmediateFeedback(form.action, 'nothing_changed') try: diff = json.loads(form.diff) except (json.JSONDecodeError, ValueError): raise ImmediateFeedback(form.action, 'inconsistent_diff') try: channelid = int(channel_id) except ValueError: raise ImmediateFeedback(form.action, 'invalid_channel/screen_id') for k, v in diff.items(): try: sub = bool(v) except ValueError: raise ImmediateFeedback(form.action, 'invalid_channel/screen_id') try: screenid = int(k) except ValueError: raise ImmediateFeedback(form.action, 'invalid_channel/screen_id') try: channel = Channel.get(channelid) if not channel.can_subscribe(u): raise self.forbidden(message="You're not allow to do that") screen = Screen.get(screenid) if not u in screen.owners: raise self.forbidden(message="You're not allow to do that") #sub true -> New subscription #sub false -> Remove subscription if sub: screen.subscribe_to(u, channel) subscribed.append(str(channel.id)) else: screen.unsubscribe_from(u, channel) unsubscribed.append(str(channel.id)) if subscribed and unsubscribed: message = "user %s has subscribed screen %d to channel(s) %s and unsubscribed from channel(s) %s" % \ (u.log_name, screen.id, ', '.join(subscribed), ', '.join(unsubscribed)) else: message = "user %s has %s screen %d to channel(s) %s" % \ (u.log_name, "subscribed" if subscribed else "unsubscribed", screen.id, ', '.join(subscribed if subscribed else unsubscribed)) logger.info(message) add_feedback("subscription", 'ok') except SQLObjectNotFound: raise ImmediateFeedback(form.action, 'invalid_channel/screen_id') except DuplicateEntryError: # if the user has checked + unchecked the same checkbox, it will appear on the diff, # we just need to do nothing. pass except SQLObjectIntegrityError: # when there id more than one subscription matching the pair channel/screen pass resp.seeother("/channels/config/%s/subscriptions" % channel_id)
def post(self, bundle_id): def wrong_channel(channel, bundle, add): """ returns True if the channel to add is the bundle itself or if the channel is a PluginChannel with disabled plugin """ return bundle.id == channel.id or add and type(channel) is PluginChannel and channel.plugin.activated != "yes" form = self.form try: bundle = ChannelBundle.get(bundle_id) u = User.get(self.session['user']['id']) diff = json.loads(form.diff) if diff == {}: logger.info('user %s submitted empty diff for bundle management %s', u.log_name, bundle.name) raise ImmediateFeedback("manage_channels", 'nothing_changed') # Do the subscription/unsubscription for every channel in the diff contained = [] not_contained = [] try: changes = [(Channel.get(channel_id), add) for channel_id, add in diff.items()] except SQLObjectNotFound: logger.warning('user %s tried to add a channel which does not exist to bundle %d', u.log_name, bundle.id) resp.forbidden() # if somebody tries to add a channel with a disabled plugin or to add a bundle to itself wrong_channels = [(channel, add) for channel, add in changes if wrong_channel(channel, bundle, add)] if wrong_channels: channel, add = wrong_channels[0] if channel.id == bundle.id: logger.warning('user %s tried to %s bundle %d to itself', u.log_name, 'add' if add else "remove", bundle.id) raise ImmediateFeedback("manage_channels", "added_to_itself") else: logger.warning('user %s tried to %s channel %d with disabled plugin to bundle %d', u.log_name, 'add' if add else "remove", channel.id, bundle.id) raise ImmediateFeedback("manage_channels", "disabled_plugin") for channel, add in changes: if add: try: bundle.add_channel(channel) except ValueError: logger.warning("user %s has made changes in channels management of bundle %d that created a " "cycle of bundles by adding channel %d (%s)", u.log_name, bundle.id, channel.id, channel.name) form.channel_name = channel.name raise ImmediateFeedback("manage_channels", "bundle_cycle") contained.append(str(channel.id)) else: bundle.remove_channel(channel) not_contained.append(str(channel.id)) if contained and not_contained: message = "user %s has added to channel(s) %s and removed channel(s) %s to bundle %d" % \ (u.log_name, ', '.join(contained), ', '.join(not_contained), bundle.id) else: message = "user %s has %s channel(s) %s to bundle %d" % \ (u.log_name, "added" if contained else "removed", ', '.join(contained if contained else not_contained), bundle.id) logger.info(message) add_feedback("manage_channels", 'ok') except SQLObjectNotFound: resp.notfound() except ImmediateFeedback: pass store_form(form) resp.seeother("/channels/config/%s/manage_bundle" % bundle.id)
def post(self, capsuleid, channel): try: caps_db = EditorCapsule.get(int(capsuleid)) slides = caps_db.slides form = self.form logger_extra = {'channel_name': channel.name, 'channel_id': channel.id} logger = get_logger('editor', channel) if caps_db.channel != channel: return "there is no capsule with the id " + str(capsuleid) + " in the channel " + str(channel.id) if form.action == 'delete': try: slide = EditorSlide.get(int(form.id)) except ValueError: return "this is not a valid slide id" except SQLObjectNotFound: return "there is no slide with the id " + form.id + " in the channel " + str(channel.id) slide.destroySelf() slides = EditorSlide.rectify_s_order(capsuleid) elif form.action == 'duplicate': try: slide = EditorSlide.get(int(form.id)) except ValueError: return "this is not a valid slide id" except SQLObjectNotFound: return "there is no slide with the id " + form.id + " in the channel " + str(channel.id) duplicate = slide.duplicate(s_order=-1) caps_db.insert_slide_at(duplicate, slide.s_order + 1) slides = caps_db.slides elif form.action == 'order': try: new_order = json.loads(form.order) except AttributeError: return "you seem to try to change the order of slides that doesn't exist..." except JSONDecodeError: return "invalid changes" for k, v in new_order.items(): try: slide = EditorSlide.get(int(k)) if slide.capsule.id != int(capsuleid): return "you try to change the order of a slide in a different capsule..." slide.s_order = int(v) except ValueError: return "invalid changes" except SQLObjectNotFound: return "You try to change the order of slides that doesn't exist..." slides = EditorSlide.rectify_s_order(capsuleid) elif form.action == 'theme': caps_db = EditorCapsule.get(int(capsuleid)) if caps_db.channel != channel: return "there is no capsule with the id " + str(capsuleid) + " in the channel " + str(channel.id) if form.theme not in Themes: raise ImmediateFeedback(form.action, 'not_existing_theme') caps_db.theme = form.theme elif form.action == 'edit': try: name = form.name.strip() capsule = caps_db if not name: raise ValueError('name') date_from = datetime.datetime.strptime(form['date-from'], "%Y-%m-%dT%H:%M:%S%z") date_to = datetime.datetime.strptime(form['date-to'], "%Y-%m-%dT%H:%M:%S%z") if date_to <= date_from: raise ValueError('dates') capsule.name = name capsule.validity_from = date_from capsule.validity_to = date_to except SQLObjectNotFound: return seeother(channel.id, '/') except DuplicateEntryError: raise ImmediateFeedback(form.action, 'name_already_exists') except ValueError as e: raise ImmediateFeedback(form.action, 'invalid_name' if e.args[0] == 'name' else 'dates_inverted') elif form.action.startswith('import'): storage_manager = StorageManager(channel.id) capsule = caps_db background_color = 'white' if 'white-background' in form and form['white-background'] == 'on' else 'black' offset = EditorSlide.selectBy(capsule=capsule).max('s_order') offset = offset + 1 if offset is not None else 0 if form.action == 'import-slides' and 'pdf' in form: slide_files = [] try: with Color(background_color) as bg: with Image(blob=form.pdf.read(), resolution=150) as pdf: for i, page in enumerate(pdf.sequence): img_page = Image(image=page) img_page.background_color = bg img_page.alpha_channel = False img_page.format = 'jpeg' img_page.transform(resize='1920x1080>') asset = storage_manager.store_file(img_page.make_blob('jpeg'), filename='import-capsule-%d-slide-%d.jpeg' % (capsule.id, offset + i), user=self.session['user']['id']) slide_files.append(asset) slide_duration = channel.get_config_param('duration') * 1000 for i, slide_file in enumerate(slide_files): s = EditorSlide(duration=slide_duration, content={'background-1': {'file': slide_file.id, 'size': 'contain', 'color': background_color}}, s_order=offset + i, template='template-image-bg', capsule=capsule) AssetSlideMapping(assetID=slide_file.id, slideID=s.id) except (ValueError, TypeError): logger.warning('An Exception has been encountered when importing PDF file:', extra=logger_extra, exc_info=True) elif form.action == 'import-video' and 'video' in form: try: video_slide = EditorSlide.from_video(form.video, storage_manager, self.transcoding_queue, capsule, self.session['user']['id'], background_color) if type(video_slide) is str: # Video is being transcoded raise ImmediateFeedback(form.action, 'video_transcoding', video_slide) except TypeError as e: raise ImmediateFeedback(form.action, 'invalid_video_format', e.type) else: resp.badrequest() elif form.action == 'duration': try: slide_id = int(form.id) slide = EditorSlide.get(slide_id) if "duration" in form: duration = float(form.duration)*1000 if duration < 0: raise ImmediateFeedback(form.action, "negative_slide_duration") else: duration = -1 slide.duration = duration except SQLObjectNotFound: return seeother(channel.id, '/') except ValueError: raise ImmediateFeedback(form.action, 'invalid_slide_duration') add_feedback(form.action, 'ok') except ValueError: return "this is not a valid capsule id" except SQLObjectNotFound: return "there is no capsule with the id " + str(capsuleid) + " in the channel " + str(channel.id) except ImmediateFeedback: store_form(form) return self.render_page(channel=channel, capsule=caps_db, slides=caps_db.slides)
def post(self): """ Handles screen creation, editing, deletion, channel subscriptions. """ form = self.form u = User.get(self.session['user']['id']) try: if form.action == 'delete': if not u.super_admin: resp.forbidden() try: screenid = int(form.screenid) except ValueError: raise ImmediateFeedback(form.action, 'invalid_id') try: Screen.delete(screenid) raise ImmediateFeedback(form.action, 'ok') except SQLObjectNotFound as e: raise ImmediateFeedback(form.action, 'no_id_matching') elif form.action == 'subscribe': if form.diff == 'diff': raise ImmediateFeedback(form.action, 'nothing_changed') try: diff = json.loads(form.diff) except (json.JSONDecodeError, ValueError): raise ImmediateFeedback(form.action, 'inconsistent_diff') try: screenid = int(form.screenid) except ValueError: raise ImmediateFeedback(form.action, 'invalid_channel/screen_id') for k, v in diff.items(): try: sub = bool(v) except ValueError: raise ImmediateFeedback(form.action, 'invalid_channel/screen_id') try: channelid = int(k) except ValueError: raise ImmediateFeedback(form.action, 'invalid_channel/screen_id') try: channel = Channel.get(channelid) screen = Screen.get(screenid) if UserPermissions.administrator not in u.highest_permission_level and not ( channel.can_subscribe(u) and u in screen.owners): resp.forbidden() if sub: if hasattr(channel, "plugin" ) and channel.plugin.activated != 'yes': resp.forbidden() screen.subscribe_to(user=u, channel=channel) else: screen.unsubscribe_from(user=u, channel=channel) except SQLObjectNotFound: raise ImmediateFeedback(form.action, 'invalid_channel/screen_id') except DuplicateEntryError: # if the user has checked + unchecked the same checkbox, it will appear on the diff, # we just need to do nothing. pass except SQLObjectIntegrityError: # when there id more than one subscription matching the pair channel/screen # TODO: log something pass elif form.action == 'chown': if form.diff == 'diff': raise ImmediateFeedback(form.action, 'nothing_changed') try: diff = json.loads(form.diff) except (json.JSONDecodeError, ValueError): raise ImmediateFeedback(form.action, 'inconsistent_diff') try: screenid = int(form.screenid) except ValueError: raise ImmediateFeedback(form.action, 'screenid') for k, v in diff.items(): try: own = bool(v) except ValueError: raise ImmediateFeedback(form.action, 'invalid_screen/user_id') try: userid = int(k) except ValueError: raise ImmediateFeedback(form.action, 'invalid_screen/user_id') try: screen = Screen.get(screenid) if UserPermissions.administrator not in u.highest_permission_level and u not in screen.owners: resp.forbidden() user = User.get(userid) if own: screen.safe_add_user(user) else: screen.removeUser(user) except SQLObjectNotFound: raise ImmediateFeedback(form.action, 'invalid_screen/user_id') except DuplicateEntryError: # if the user has checked + unchecked the same checkbox, it will appear on the diff, # we just need to do nothing. pass except SQLObjectIntegrityError: # when there is more than one subscription mathing the pair channel/screen # TODO: log something pass elif form.action == 'configure': screen = Screen.get(int(form.id)) screen.shuffle = form.get('shuffle') == 'on' screen.show_postit = form.get('postit') == 'on' screen.show_slide_number = form.get( 'show_slide_number') == 'on' else: building = Building.get(form.building.strip()) name = form.name.strip() form.building_name = None if not building: raise ImmediateFeedback(form.action, 'empty_building') form.building_name = building.name if not name: raise ImmediateFeedback(form.action, 'empty_name') if len(name) > Screen.sqlmeta.columns['name'].length: raise ImmediateFeedback(form.action, 'too_long_name') try: macs = { self.check_mac_address(mac) for mac in form.mac.strip().lower().split(';') if mac } except ValueError: raise ImmediateFeedback(form.action, 'invalid_mac_address') if form.action == 'create': if UserPermissions.administrator not in u.highest_permission_level: resp.forbidden() try: screen = Screen(name=form.name.strip(), building=form.building, location=form.location.strip(), comment=form.comment.strip(), orientation=form.orientation) except DuplicateEntryError: raise ImmediateFeedback(form.action, 'name_already_exists') elif form.action == 'edit': if UserPermissions.administrator not in u.highest_permission_level: resp.forbidden() try: screenid = int(form.screenid) except ValueError: raise ImmediateFeedback(form.action, 'invalid_id') screen = Screen.get(screenid) if screen is None: raise ImmediateFeedback(form.action, 'no_id_matching') try: screen.name = form.name.strip() screen.building = form.building screen.orientation = form.orientation except DuplicateEntryError: raise ImmediateFeedback(form.action, 'name_already_exists') screen.location = form.location.strip() screen.comment = form.comment.strip() else: raise NotImplementedError try: screen_macs = [ screen_mac.mac for screen_mac in screen.macs ] for mac in screen_macs: if mac not in macs: ScreenMac.selectBy(mac=mac).getOne().destroySelf() for mac in macs: if mac not in screen_macs: ScreenMac(screen=screen, mac=mac) except DuplicateEntryError: raise ImmediateFeedback(form.action, 'mac_already_exists') add_feedback(form.action, 'ok') except ImmediateFeedback: pass store_form(form) return self.render_page()
def POST(self, channel): form = web.input( pdf={}, video={} ) # Force CGI FieldStorage object to be created for large files logger_extra = {'channel_name': channel.name, 'channel_id': channel.id} logger = get_logger('editor', channel) capsules = None try: if form['action'] == 'delete': try: capsule_id = int(form['id']) except ValueError: raise ImmediateFeedback(form.action, 'invalid_id') try: capsule = EditorCapsule.get(capsule_id) except SQLObjectNotFound: raise ImmediateFeedback(form.action, 'no_id_matching') if channel != capsule.channel: raise ImmediateFeedback(form.action, 'wrong_channel') if capsule is None: raise ImmediateFeedback(form.action, 'no_id_matching') capsule.destroySelf() capsules = EditorCapsule.rectify_c_order(channel.id) elif form['action'] == 'duplicate': try: capsule_id = int(form['id']) except ValueError: raise ImmediateFeedback(form.action, 'invalid_id') try: capsule = EditorCapsule.get(capsule_id) except SQLObjectNotFound: raise ImmediateFeedback(form.action, 'no_id_matching') if channel != capsule.channel: raise ImmediateFeedback(form.action, 'wrong_channel') if capsule is None: raise ImmediateFeedback(form.action, 'no_id_matching') capsule.duplicate(owner_id=self.session['user']['id']) capsules = EditorCapsule.rectify_c_order(channel.id) elif form.action == 'order': try: new_order = json.loads(form.order) except AttributeError: return "you seem to try to change the order of slides that doesn't exist..." except JSONDecodeError: return "invalid changes" capsules_to_reorder = {} for k in new_order.keys(): try: capsule = EditorCapsule.get(int(k)) capsules_to_reorder[k] = capsule if capsule.channel.id != channel.id: return "you try to change the order of a capsule in a different channel..." except SQLObjectNotFound: return "You try to change the order of slides that doesn't exist..." sorted_list = sorted(capsules_to_reorder.values(), key=lambda caps: caps.c_order) new_to_old_order = {} i = 0 for elem in sorted_list: new_to_old_order[i] = elem.c_order i += 1 try: for k, v in new_order.items(): capsules_to_reorder[k].c_order = new_to_old_order[int( v)] except ValueError: return "invalid changes" capsules = EditorCapsule.rectify_c_order(channel.id) elif form['action'] == 'create' or form['action'].startswith( 'import'): name = form['name'].strip() if not name: raise ImmediateFeedback(form.action, 'invalid_name') try: if 'date-from' in form and 'date-to' in form: try: date_from = datetime.datetime.strptime( form['date-from'], "%Y-%m-%dT%H:%M:%S%z") date_to = datetime.datetime.strptime( form['date-to'], "%Y-%m-%dT%H:%M:%S%z") except ValueError: raise ImmediateFeedback(form.action, 'wrong_date_values') else: if 'capsule_validity' in channel.plugin_config: validity = int( channel.plugin_config['capsule_validity']) else: validity = int( channel.plugin. channels_params['capsule_validity']['default']) date_from = datetime.datetime.now() time_delta = datetime.timedelta(hours=validity) date_to = date_from + time_delta if date_to <= date_from: raise ImmediateFeedback(form.action, 'dates_inverted') capsule = EditorCapsule( name=form['name'], channel=channel, ownerID=self.session['user']['id'], creation_date=datetime.datetime.now(), c_order=EditorCapsule.select().count(), validity_from=date_from, validity_to=date_to) if form.action.startswith('import'): storage_manager = StorageManager(channel.id) background_color = 'white' if 'white-background' in form and form[ 'white-background'] == 'on' else 'black' if form.action == 'import-capsule' and 'pdf' in form: slide_files = [] try: with Color(background_color) as bg: with Image(blob=form.pdf.file.read(), resolution=150) as pdf: for i, page in enumerate(pdf.sequence): img_page = Image(image=page) img_page.background_color = bg img_page.alpha_channel = False img_page.format = 'jpeg' img_page.transform( resize='1920x1080>') slide_files.append( storage_manager.store_file( img_page.make_blob('jpeg'), filename= 'import-capsule-%d-slide-%d.jpeg' % (capsule.id, i), user=self.session['user'] ['id'])) slide_duration = channel.get_config_param( 'duration') * 1000 for i, slide_file in enumerate(slide_files): s = EditorSlide( duration=slide_duration, content={ 'background-1': { 'file': slide_file.id, 'size': 'contain', 'color': background_color } }, s_order=i, template='template-image-bg', capsule=capsule) AssetSlideMapping(assetID=slide_file.id, slideID=s.id) except (ValueError, TypeError): logger.warning( 'An Exception has been encountered when importing PDF file:', extra=logger_extra, exc_info=True) elif form.action == 'import-video' and 'video' in form: try: video_slide = EditorSlide.from_video( form.video, storage_manager, self.transcoding_queue, capsule, self.session['user']['id'], background_color) if type(video_slide ) is str: # Video is being transcoded raise ImmediateFeedback( form.action, 'video_transcoding', video_slide) except TypeError as e: capsule.destroySelf() raise ImmediateFeedback( form.action, 'invalid_video_format', e.type if hasattr(e, 'type') else None) else: raise web.badrequest() except DuplicateEntryError: raise ImmediateFeedback(form.action, 'name_already_exists') elif form['action'] == 'edit': name = form['name'].strip() if not name: raise ImmediateFeedback(form.action, 'invalid_name') try: capsule_id = int(form['id']) except ValueError: raise ImmediateFeedback(form.action, 'invalid_id') try: capsule = EditorCapsule.get(capsule_id) except SQLObjectNotFound: raise ImmediateFeedback(form.action, 'no_id_matching') if channel != capsule.channel: raise ImmediateFeedback(form.action, 'wrong_channel') try: capsule.name = name except DuplicateEntryError: raise ImmediateFeedback(form.action, 'name_already_exists') try: date_from = datetime.datetime.strptime( form['date-from'], "%Y-%m-%dT%H:%M:%S%z") date_to = datetime.datetime.strptime( form['date-to'], "%Y-%m-%dT%H:%M:%S%z") except ValueError: raise ImmediateFeedback(form.action, 'wrong_date_values') if date_to <= date_from: raise ImmediateFeedback(form.action, 'dates_inverted') capsule.validity_from = date_from capsule.validity_to = date_to add_feedback(form.action, 'ok') except ImmediateFeedback: pass store_form(form) return self.render_page(channel, capsules)
def POST(self): """ Handles channel creation, editing, deletion, configuration and user permissions. """ form = web.input() current_user = User.get(self.session['user']['id']) channel = None try: if form.action.startswith('create') or form.action.startswith( 'edit'): # Prepare creation or edition of channels/bundles name = form.name.strip() description = form.description if form.description and form.description.strip( ) else None enabled = form.get('enabled') == 'on' if form.subscription_right not in [ 'public', 'restricted', 'private' ]: raise ImmediateFeedback(form.action, 'invalid_subscription_right') if len(name) < 3: raise ImmediateFeedback(form.action, 'invalid_name') if form.action.startswith('create'): if UserPermissions.administrator not in current_user.highest_permission_level: logger.warning( 'user %s tried to create a channel without being admin', current_user.log_name) raise web.forbidden() try: if form.action == 'create-channel': try: plugin_id = int(form.plugin) except ValueError: raise ImmediateFeedback(form.action, 'invalid_plugin') p = Plugin.get(plugin_id) channel = PluginChannel( name=name, plugin=p, subscription_right=form.subscription_right, description=description, enabled=enabled) if p.webapp: self.plugin_manager.add_mapping(self.app, channel) elif form.action == 'create-bundle': channel = ChannelBundle( name=name, description=description, subscription_right=form.subscription_right, enabled=enabled) else: raise web.badrequest() except SQLObjectNotFound: raise ImmediateFeedback(form.action, 'invalid_plugin') except DuplicateEntryError: raise ImmediateFeedback(form.action, 'name_already_exists') logger.info('channel ' + channel.name + ' created by ' + current_user.log_name) elif form.action.startswith('edit'): if UserPermissions.administrator not in current_user.highest_permission_level: raise web.forbidden() try: form.id = int(form.id) channel = (PluginChannel if form.action == 'edit-channel' else Channel).get(form.id) except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') previous_state = { 'name': channel.name, 'description': channel.description, 'subscription_right': channel.subscription_right, 'enabled': channel.enabled } new_state = { 'name': name, 'description': description, 'subscription_right': form.subscription_right, 'enabled': enabled } state_diff = dict( set(new_state.items()) - set(previous_state.items())) if form.action == 'edit-channel': try: plugin_id = int(form.plugin) p = Plugin.get(plugin_id) add_mapping = p.webapp and channel.plugin != p previous_state['plugin'] = channel.plugin new_state['plugin'] = p except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_plugin') elif form.action == 'edit-bundle': pass # There is nothing more to edit for a bundle than a channel else: raise web.badrequest() try: channel.set(**new_state) except DuplicateEntryError: channel.set(**previous_state) # Rollback raise ImmediateFeedback(form.action, 'name_already_exists') logger.info( '[Channel %s (%d)] ' % (channel.name, channel.id) + current_user.log_name + ' edited the channel.\n' 'Previous state: %s\n' % str({ k: v for k, v in previous_state.items() if k in state_diff }) + 'New state: %s' % str(state_diff)) if form.action == 'edit-channel' and add_mapping: self.plugin_manager.add_mapping(self.app, channel) elif form.action.startswith('delete'): if not current_user.super_admin: logger.warning( 'the user %s tried to delete a channel without having the rights to do it', current_user.log_name) raise web.forbidden() try: form.id = int(form.id) channel = Channel.get(form.id) if channel.subscriptions.count( ) > 0 and 'confirm-delete' not in form: raise ImmediateFeedback( form.action, 'channel_has_subscriptions', { 'channel': { 'name': channel.name, 'id': channel.id, 'description': channel.description, 'subscription_right': channel.subscription_right }, 'plugin_id': channel.plugin.id if form.action == 'delete-channel' else None, 'subscriptions': [(s.screen.id, s.screen.name, s.screen.building.name) for s in channel.subscriptions] }) form.name = channel.name channel_name = channel.name channel.destroySelf() logger.info('the channel %s has been deleted by user %s', channel_name, current_user.log_name) except (SQLObjectNotFound, ValueError) as e: print(e) raise ImmediateFeedback(form.action, 'invalid_id') elif form.action == 'add-users-channel': try: if 'users' not in form: raise web.badrequest() form.users = json.loads(form.users) form.id = int(form.id) channel = PluginChannel.get(form.id) if not channel.has_admin( current_user ) and UserPermissions.administrator not in current_user.highest_permission_level: raise web.forbidden() form.name = channel.name for user_id, diff in form.users.items(): user_id = int(user_id) user = User.get(user_id) if 'permission' in diff: permission_level = diff['permission'] new_permission_level = UserPermissions( permission_level) old_permission_level = channel.get_channel_permissions_of( user) if new_permission_level == UserPermissions.no_permission \ and (UserPermissions.administrator in current_user.highest_permission_level or old_permission_level == UserPermissions.channel_contributor): channel.remove_permission_to_user(user) logger.info( 'permissions of user %s concerning channel %s have been removed by user %s', user.log_name, channel.name, current_user.log_name) elif (new_permission_level == UserPermissions.channel_contributor and channel.has_admin( current_user) and old_permission_level == UserPermissions.no_permission) \ or (new_permission_level in UserPermissions.channel_administrator and UserPermissions.administrator in current_user.highest_permission_level): channel.give_permission_to_user( user, new_permission_level) logger.info( 'permissions of user %s concerning channel %s have been set to %s by user %s', user.log_name, channel.name, UserPermissions.get_permission_string( new_permission_level), current_user.log_name) if 'authorized_subscriber' in diff: authorized_subscriber = diff[ 'authorized_subscriber'] if authorized_subscriber and ( user not in channel.authorized_subscribers): channel.addUser(user) logger.info( 'the user %s has been added to channel %s as authorized subscriber by user %s', user.log_name, channel.name, current_user.log_name) elif not authorized_subscriber and ( user in channel.authorized_subscribers): channel.removeUser(user) logger.info( 'the user %s has been removed from channel %s as authorized subscriber by user %s', user.log_name, channel.name, current_user.log_name) except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') except (KeyError, json.JSONDecodeError): raise ImmediateFeedback(form.action, 'invalid_users') elif form.action == 'configure': try: form.id = int(form.id) channel = PluginChannel.get(form.id) pattern = re.compile(r'list\[.*\]') if UserPermissions.administrator in current_user.highest_permission_level or UserPermissions.channel_administrator in channel.get_channel_permissions_of( current_user) or channel.has_contrib(current_user): for k, v in [(k, v) for k, v in channel.plugin.channels_params.items() if channel.get_access_rights_for( k, current_user)[1]]: # Iterates on the parameters the current user can write to if v['type'] == 'bool': value = k in form and form[k] == 'on' elif v['type'] == 'int': value = int(form[k]) if not (v.get('min', float('-inf')) <= value <= v.get('max', float('inf'))): continue elif pattern.match(v['type']): inner_type = v['type'][5:-1] if inner_type == 'string': value = web.input(**{k: ['']})[k] elif pattern.match(inner_type): inner_type = inner_type[5:-1] if inner_type == 'string': delimiter = form[k + '-delimiter'] values = web.input(**{k: ['']})[k] lists = [] l = [] for v in values: if v == delimiter: lists.append(l) l = [] else: l.append(v) value = lists elif k in form: if v['type'] == 'template' and form[k] == '~': value = None else: value = form[k] else: continue if channel.get_config_param(k) != value: channel.plugin_config[k] = value logger.info( 'the %s parameter of channel %s has been changed to %s by user %s', k, channel.name, value, current_user.log_name) if current_user.super_admin: channel.cache_activated = 'cache-activated' in form and form[ 'cache-activated'] == 'on' channel.cache_validity = int( form['cache-validity'] ) if 'cache-validity' in form and form[ 'cache-validity'] else channel.cache_validity channel.keep_noncomplying_capsules = 'keep-capsules' in form and form[ 'keep-capsules'] == 'on' channel.plugin_config = channel.plugin_config # Force SQLObject update try: self.plugin_manager.invalidate_cache( channel.plugin.name, channel.id) self.plugin_manager.get_plugin( channel.plugin.name).get_content(channel.id) except MisconfiguredParameters as e: for faulty_param in e: add_feedback(form.action, faulty_param[0], faulty_param) raise web.seeother('/channels/%d' % channel.id) except Exception as e: add_feedback(form.action, 'general_error', str(e)) raise web.seeother('/channels/%d' % channel.id) else: raise web.forbidden() form.name = channel.name except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') if channel: form.name = channel.name add_feedback(form.action, 'ok') except ImmediateFeedback: if channel is not None and channel.enabled: form.enabled = 'on' store_form(form) return self.render_page(current_user)
def post(self): """ Handles user creation, editing and deletion. """ form = self.form super_admin = form.get('super_admin', False) == 'on' admin = form.get('admin', False) == 'on' if super_admin: admin = False current_user = User.get(self.session['user']['id']) try: if form.action == 'create': username = form.username.strip() fullname = form.fullname.strip() form.email = form.email.strip() email = None if len(form.email) == 0 or not self.pattern.match( form.email) else form.email if email is None and len(form.email) != 0: raise ImmediateFeedback(form.action, 'invalid_email') if len(email) > User.sqlmeta.columns['email'].length: raise ImmediateFeedback(form.action, 'too_long_email') if len(username) > User.sqlmeta.columns['username'].length: raise ImmediateFeedback(form.action, 'too_long_username') if not username: username = None elif len(username) < 3: raise ImmediateFeedback(form.action, 'invalid_username') try: User(username=username, fullname=fullname, email=email, super_admin=super_admin, disabled=False) except DuplicateEntryError: u = User.selectBy(email=form.email).getOne(None) if u is not None: raise ImmediateFeedback(form.action, 'email_already_exists') u = User.selectBy(username=username).getOne(None) if u is not None: raise ImmediateFeedback(form.action, 'username_already_exists') elif form.action == 'edit': try: form.id = int(form.id) u = User.get(form.id) form.email = form.email.strip() email = None if len( form.email) == 0 or not self.pattern.match( form.email) else form.email form.username = u.username form.fullname = u.fullname if email is None and len(form.email) != 0: raise ImmediateFeedback(form.action, 'invalid_email') if email: try: u.email = email except DuplicateEntryError: raise ImmediateFeedback(form.action, 'email_already_exists') form.email = u.email if len(email) > User.sqlmeta.columns['email'].length: raise ImmediateFeedback(form.action, 'too_long_email') if not current_user.super_admin: if u.super_admin: resp.forbidden() else: if self.session['user']['id'] != form.id: u.set(super_admin=super_admin, admin=admin) except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') elif form.action == 'toggle-activation': if not current_user.super_admin: resp.forbidden() try: form.id = int(form.id) u = User.get(form.id) form.email = u.email u.disabled = not u.disabled add_feedback( form.action, 'activated' if not u.disabled else 'deactivated') except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') add_feedback(form.action, 'ok') except ImmediateFeedback: pass store_form(form) resp.seeother('/users')