class AdvertisingForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.AdvertisingForm fields = [ ListFieldSet( 'advanced', suppress_label=True, legend='', css_classes=['details_fieldset'], children=[ TextArea('advertising_banner_html', label_text=N_('Banner HTML'), attrs=dict(rows=15, cols=25)), TextArea('advertising_sidebar_html', label_text=N_('Sidebar HTML'), attrs=dict(rows=15, cols=25)), ], ), SubmitButton('save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), ]
class TagForm(ListForm): template = 'admin/tags_and_categories_form.html' id = None css_classes = ['form', 'tag-form'] submit_text = None event = events.Admin.TagForm # required to support multiple named buttons to differentiate between Save & Delete? _name = 'vf' fields = [ TextField('name', label_text=N_('Name'), css_classes=['tag-name'], validator=TagNameValidator(not_empty=True)), TextField('slug', label_text=N_('Permalink'), css_classes=['tag-slug'], validator=NotEmpty), ResetButton('cancel', default=N_('Cancel'), css_classes=['btn', 'f-lft', 'btn-cancel']), SubmitButton('save', default=N_('Save'), css_classes=['f-rgt', 'btn', 'blue', 'btn-save']), ]
class UploadForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.UploadForm fields = [ TextField('max_upload_size', label_text=N_('Max. allowed upload file size in megabytes'), validator=MegaByteValidator(not_empty=True, min=0)), ListFieldSet('legal_wording', suppress_label=True, legend=N_('Legal Wording:'), css_classes=['details_fieldset'], children=[ XHTMLTextArea('wording_user_uploads', label_text=N_('User Uploads'), attrs=dict(rows=15, cols=25)), ]), SubmitButton('save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), ]
class GroupForm(ListForm): template = 'admin/box-form.html' id = 'group-form' css_class = 'form' submit_text = None show_children_errors = True event = events.Admin.GroupForm fields = [ TextField('display_name', label_text=N_('Display Name'), validator=TextField.validator(not_empty=True), maxlength=255), TextField('group_name', label_text=N_('Groupname'), validator=All(PlainText(not_empty=True), UniqueGroupname()), maxlength=16), CheckBoxList( 'permissions', label_text=N_('Group Permissions'), css_classes=['details_fieldset'], options=lambda: DBSession.query(Permission.permission_id, Permission.description).all()), SubmitButton('save', default=N_('Save'), named_button=True, css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), SubmitButton('delete', default=N_('Delete'), named_button=True, css_classes=['btn', 'btn-delete']), ]
class LoginForm(ListForm): template = 'forms/box_form.html' method = 'POST' id = 'login-form' css_class = 'form clearfix' submit_text = None # For login failures we display only a generic (bad username or password) # error message which is not related to any particular field. # However I'd like to mark the input widgets as faulty without displaying # the dummy errors (injected by LoginController programmatically as this # form is not used for credential validation) so this will prevent the error # text from being displayed. However the actual input fields will be marked # with css classes anyway. show_children_errors = False fields = [ TextField('login', label_text=N_('Username'), # 'autofocus' is actually not XHTML-compliant attrs={'autofocus': True}), PasswordField('password', label_text=N_('Password')), SubmitButton('login_button', default=N_('Login'), css_classes=['mcore-btn', 'btn-submit', 'f-rgt']) ] def post_init(self, *args, **kwargs): events.LoginForm(self)
class PopularityForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.PopularityForm fields = [ ListFieldSet('popularity', suppress_label=True, css_classes=['details_fieldset'], legend=N_('Popularity Algorithm Variables:'), children=[ TextField('popularity_decay_exponent', validator=Int(not_empty=True, min=1), label_text=N_('Decay Exponent')), TextField('popularity_decay_lifetime', validator=Int(not_empty=True, min=1), label_text=N_('Decay Lifetime')), ]), SubmitButton('save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), ]
class AddFileForm(ListForm): template = 'admin/media/file-add-form.html' id = 'add-file-form' submit_text = None event = events.Admin.AddFileForm fields = [ FileField( 'file', label_text=N_( 'Select an encoded video or audio file on your computer'), validator=FieldStorageUploadConverter(not_empty=False, label_text=N_('Upload'))), SubmitButton('add_url', default=N_('Add URL'), named_button=True, css_class='btn grey btn-add-url f-rgt'), TextField('url', validator=URIValidator, suppress_label=True, attrs=lambda: {'title': _('YouTube, Vimeo, Amazon S3 or any other link')}, maxlength=255), ]
class UserForm(ListForm): template = 'admin/box-form.html' id = 'user-form' css_class = 'form' submit_text = None show_children_errors = True _name = 'user-form' # TODO: Figure out why this is required?? event = events.Admin.UserForm fields = [ TextField('display_name', label_text=N_('Display Name'), validator=TextField.validator(not_empty=True), maxlength=255), TextField('email_address', label_text=N_('Email Address'), validator=email_validator(not_empty=True), maxlength=255), ListFieldSet('login_details', suppress_label=True, legend=N_('Login Details:'), css_classes=['details_fieldset'], validator = Schema(chained_validators=[ FieldsMatch('password', 'confirm_password', messages={'invalidNoMatch': N_("Passwords do not match"),})] ), children=[ CheckBoxList('groups', label_text=N_('Groups'), options=lambda: Group.custom_groups(Group.group_id, Group.display_name).all()), TextField('user_name', label_text=N_('Username'), maxlength=16, validator=All(PlainText(), UniqueUsername(not_empty=True))), PasswordField('password', label_text=N_('Password'), validators=NotEmpty, maxlength=80, attrs={'autocomplete': 'off'}), PasswordField('confirm_password', label_text=N_('Confirm password'), validators=NotEmpty, maxlength=80, attrs={'autocomplete': 'off'}), ] ), SubmitButton('save', default=N_('Save'), named_button=True, css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), SubmitButton('delete', default=N_('Delete'), named_button=True, css_classes=['btn', 'btn-delete']), ]
class fields(WidgetsList): body = TextArea(validator=NotEmpty, label_text=N_('Comment'), attrs=dict(rows=5, cols=25)) submit = SubmitButton(default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']) cancel = ResetButton(default=N_('Cancel'), css_classes=['btn', 'btn-cancel'])
class LocalFileStorageForm(StorageForm): event = events.Admin.Storage.LocalFileStorageForm fields = StorageForm.fields + [ ListFieldSet('specifics', suppress_label=True, legend=N_('Options specific to Local File Storage:'), children=[ TextField('path', label_text=N_('Path to store files under'), help_text=N_('Defaults to the "data_dir" from your INI file.'), ), TextField('rtmp_server_uri', label_text=N_('RTMP Server URL'), help_text=N_('Files must be accessible under the same name as they are stored with locally.'), ), ], ) ] + StorageForm.buttons def display(self, value, engine, **kwargs): """Display the form with default values from the given StorageEngine. If the value dict is not fully populated, populate any missing entries with the values from the given StorageEngine's :attr:`_data <mediadrop.lib.storage.StorageEngine._data>` dict. :param value: A (sparse) dict of values to populate the form with. :type value: dict :param engine: An instance of the storage engine implementation. :type engine: :class:`mediadrop.lib.storage.StorageEngine` subclass """ specifics = value.setdefault('specifics', {}) specifics.setdefault('path', engine._data.get('path', None)) specifics.setdefault('rtmp_server_uri', engine._data.get('rtmp_server_uri', None)) return StorageForm.display(self, value, engine, **kwargs) def save_engine_params(self, engine, **kwargs): """Map validated field values to engine data. Since form widgets may be nested or named differently than the keys in the :attr:`mediadrop.lib.storage.StorageEngine._data` dict, it is necessary to manually map field values to the data dictionary. :type engine: :class:`mediadrop.lib.storage.StorageEngine` subclass :param engine: An instance of the storage engine implementation. :param \*\*kwargs: Validated and filtered form values. :raises formencode.Invalid: If some post-validation error is detected in the user input. This will trigger the same error handling behaviour as with the @validate decorator. """ StorageForm.save_engine_params(self, engine, **kwargs) specifics = kwargs['specifics'] engine._data['path'] = specifics['path'] or None engine._data['rtmp_server_uri'] = specifics['rtmp_server_uri'] or None
class fields(WidgetsList): name = TextField(validator=TextField.validator(not_empty=True), label_text=N_('Name')) slug = TextField(validator=NotEmpty, label_text=N_('Permalink')) parent_id = SingleSelectField(label_text=N_('Parent Category'), options=category_options) cancel = ResetButton(default=N_('Cancel'), css_classes=['btn', 'f-lft', 'btn-cancel']) save = SubmitButton(default=N_('Save'), named_button=True, css_classes=['f-rgt', 'btn', 'blue', 'btn-save'])
class GoogleAPIForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.CommentsForm fields = [ TextField('google_apikey', label_text=N_('Google API key'), help_text=N_('See https://console.developers.google.com/')), SubmitButton('save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), ]
class PlayerPrefsForm(ListForm): template = 'admin/box-form.html' id = 'player-form' css_class = 'form playerform' submit_text = None show_children_errors = True _name = 'player-form' # TODO: Figure out why this is required?? params = ['player'] fields = [ ListFieldSet( 'general', legend=N_('General Options:'), suppress_label=True, children=[ TextField( 'display_name', label_text=N_('Display Name'), validator=TextField.validator(not_empty=True), maxlength=100, ), ], ), ] buttons = [ SubmitButton( 'save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt'], ), ] def display(self, value, player, **kwargs): """Display the form with default values from the given player. If the value dict is not fully populated, populate any missing entries with the values from the given player's :attr:`_data <mediadrop.model.player.PlayerPrefs._data>` dict. :param value: A (sparse) dict of values to populate the form with. :type value: dict :param player: The player prefs mapped object to retrieve the default values from. :type player: :class:`mediadrop.model.player.PlayerPrefs` subclass """ return ListForm.display(self, value, **kwargs) def save_data(self, player, **kwargs): """Map validated field values to `PlayerPrefs.data`.
class AnalyticsForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.AnalyticsForm fields = [ ListFieldSet('google', suppress_label=True, legend=N_('Google Analytics Details:'), css_classes=['details_fieldset'], children=[ TextField('google_analytics_uacct', maxlength=255, label_text=N_('Tracking Code')), ]), SubmitButton('save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), ]
class HTML5OrFlashPrefsForm(PlayerPrefsForm): fields = [ RadioButtonList( 'prefer_flash', options=lambda: ( (False, _('Yes, use the Flash Player when the device supports it.')), (True, _('No, use the HTML5 Player when the device supports it.')), ), css_classes=['options'], label_text=N_('Prefer the Flash Player when possible'), validator=StringBool, ), ] + PlayerPrefsForm.buttons event = events.Admin.Players.HTML5OrFlashPrefsForm def display(self, value, player, **kwargs): value.setdefault('prefer_flash', player.data.get('prefer_flash', False)) return PlayerPrefsForm.display(self, value, player, **kwargs) def save_data(self, player, prefer_flash, **kwargs): player.data['prefer_flash'] = prefer_flash
class fields(WidgetsList): file_id = TextField(validator=Int()) file_type = SingleSelectField(validator=file_type_validator, options=file_type_options, attrs={'id': None, 'autocomplete': 'off'}) duration = TextField(validator=DurationValidator, attrs={'id': None, 'autocomplete': 'off'}) width_height = TextField(validator=WXHValidator, attrs={'id': None, 'autocomplete': 'off'}) bitrate = TextField(validator=Int, attrs={'id': None, 'autocomplete': 'off'}) delete = SubmitButton(default=N_('Delete file'), named_button=True, css_class='file-delete', attrs={'id': None})
class fields(WidgetsList): name = HiddenField() slug = HiddenField() parent_id = HiddenField() delete = SubmitButton( default=N_('Delete'), css_classes=['btn', 'table-row', 'delete', 'btn-inline-delete'])
class PostCommentSchema(Schema): name = TextField.validator( not_empty=True, maxlength=50, messages={'empty': N_('Please enter your name!')}) email = email_validator() body = XHTMLValidator(not_empty=True)
class VimeoUniversalEmbedPlayer(AbstractIframeEmbedPlayer): """ Vimeo Universal Player This simple player handles media with files that stored using :class:`mediadrop.lib.storage.VimeoStorage`. This player has seamless HTML5 and Flash support. """ name = u'vimeo' """A unicode string identifier for this class.""" display_name = N_(u'Vimeo') """A unicode display name for the class, to be used in the settings UI.""" scheme = u'vimeo' """The `StorageURI.scheme` which uniquely identifies this embed type.""" def render_markup(self, error_text=None): """Render the XHTML markup for this player instance. :param error_text: Optional error text that should be included in the final markup if appropriate for the player. :rtype: ``unicode`` or :class:`genshi.core.Markup` :returns: XHTML that will not be escaped by Genshi. """ uri = self.uris[0] tag = Element('iframe', src=uri, frameborder=0, width=self.adjusted_width, height=self.adjusted_height) return tag
class NotificationsForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.NotificationsForm fields = [ ListFieldSet('email', suppress_label=True, legend=N_('Email Notifications:'), css_classes=['details_fieldset'], children=[ TextField('email_media_uploaded', validator=email_list_validator, label_text=N_('Media Uploaded'), maxlength=255), TextField('email_comment_posted', validator=email_list_validator, label_text=N_('Comment Posted'), maxlength=255), TextField('email_support_requests', validator=email_list_validator, label_text=N_('Support Requested'), maxlength=255), TextField('email_send_from', validator=email_validator, label_text=N_('Send Emails From'), maxlength=255), ]), SubmitButton('save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), ]
class GeneralForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.GeneralForm fields = [ ListFieldSet('general', suppress_label=True, legend=N_('General Settings:'), css_classes=['details_fieldset'], children=[ TextField('general_site_name', maxlength=255, label_text=N_('Site Name')), SingleSelectField('general_site_title_display_order', label_text=N_('Display Site Name'), options=title_options, ), SingleSelectField('primary_language', label_text=N_('Default Language'), # TODO v0.9.1: Change to 'Primary Language' options=languages, ), SingleSelectField('featured_category', label_text=N_('Featured Category'), options=category_options, validator=Int(), ), RadioButtonList('rich_text_editor', label_text=N_('Rich Text Editing'), options=rich_text_editors, validator=rich_text_editors_validator, ), ]), SubmitButton('save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), ]
class SublimePlayerPrefsForm(PlayerPrefsForm): event = events.Admin.Players.SublimePlayerPrefsForm fields = [ TextField('script_tag', label_text=N_('Script Tag'), help_text=N_('The unique script tag given for your site.'), ), ] + PlayerPrefsForm.buttons def display(self, value, player, **kwargs): value.setdefault('script_tag', player.data.get('script_tag', '')) return PlayerPrefsForm.display(self, value, player, **kwargs) def save_data(self, player, script_tag, **kwargs): player.data['script_tag'] = script_tag or None if not script_tag and player.enabled: player.enabled = False
class fields(WidgetsList): podcast_include = SingleSelectField( 'podcast', label_text=N_('Include in the Podcast'), css_classes=['dropdown-select'], options=lambda: [(None, None)] + DBSession.query( Podcast.id, Podcast.title).all()) title = TextField(validator=validators['title'], label_text=N_('Title:'), maxlength=255) description = XHTMLTextArea(validator=validators['description'], label_text=N_('Description:'), attrs=dict(rows=5, cols=25)) file = FileField(validator=FieldStorageUploadConverter( if_missing=None, messages={'empty': N_('Oops! You forgot to enter a file.')})) submit = SubmitButton(default=N_('Submit'), css_classes=['mcore-btn', 'btn-submit'])
class HTML5PlusFlowPlayer(AbstractHTML5Player): """ HTML5 Player with fallback to FlowPlayer. """ name = u'html5+flowplayer' """A unicode string identifier for this class.""" display_name = N_(u'HTML5 + Flowplayer Fallback') """A unicode display name for the class, to be used in the settings UI.""" settings_form_class = player_forms.HTML5OrFlashPrefsForm """An optional :class:`mediadrop.forms.admin.players.PlayerPrefsForm`.""" default_data = {'prefer_flash': False} """An optional default data dictionary for user preferences.""" supported_containers = HTML5Player.supported_containers \ | FlowPlayer.supported_containers supported_schemes = HTML5Player.supported_schemes \ | FlowPlayer.supported_schemes def __init__(self, media, uris, **kwargs): super(HTML5PlusFlowPlayer, self).__init__(media, uris, **kwargs) self.flowplayer = None self.prefer_flash = self.data.get('prefer_flash', False) self.uris = [ u for u, p in izip(uris, AbstractHTML5Player.can_play(uris)) if p ] flow_uris = [u for u, p in izip(uris, FlowPlayer.can_play(uris)) if p] if flow_uris: self.flowplayer = FlowPlayer(media, flow_uris, **kwargs) def render_js_player(self): flash = self.flowplayer and self.flowplayer.render_js_player() html5 = self.uris and super(HTML5PlusFlowPlayer, self).render_js_player() if html5 and flash: return Markup("new mcore.MultiPlayer([%s, %s])" % \ (self.prefer_flash and (flash, html5) or (html5, flash))) if html5 or flash: return html5 or flash return None def render_markup(self, error_text=None): """Render the XHTML markup for this player instance. :param error_text: Optional error text that should be included in the final markup if appropriate for the player. :rtype: ``unicode`` or :class:`genshi.core.Markup` :returns: XHTML that will not be escaped by Genshi. """ if self.uris: return super(HTML5PlusFlowPlayer, self).render_markup(error_text) return error_text or u''
class BlipTVStorage(EmbedStorageEngine): engine_type = u'BlipTVStorage' """A uniquely identifying unicode string for the StorageEngine.""" default_name = N_(u'BlipTV') url_pattern = re.compile(r'^(http(s?)://)?(\w+\.)?blip.tv/(?P<id>.+)') """A compiled pattern object that uses named groupings for matches.""" def _parse(self, url, id, **kwargs): """Return metadata for the given URL that matches :attr:`url_pattern`. :type url: unicode :param url: A remote URL string. :param \*\*kwargs: The named matches from the url match object. :rtype: dict :returns: Any extracted metadata. """ if '?' in url: url += '&skin=api' else: url += '?skin=api' req = Request(url) try: temp_data = urlopen(req) xmlstring = temp_data.read() try: try: xmltree = ElementTree.fromstring(xmlstring) except: temp_data.close() raise except SyntaxError: raise UserStorageError( _('Invalid BlipTV URL. This video does not exist.')) except URLError, e: log.exception(e) raise asset = xmltree.find('payload/asset') meta = {'type': VIDEO} embed_lookup = asset.findtext('embedLookup') meta['unique_id'] = '%s %s' % (id, embed_lookup) meta['display_name'] = asset.findtext('title') meta['description'] = asset.findtext('description') meta['duration'] = int( asset.findtext('mediaList/media/duration') or 0) or None # meta['bitrate'] = int(xmltree.findtext('audiobitrate') or 0)\ # + int(xmltree.findtext('videobitrate') or 0) or None return meta
class iTunesPlayer(FileSupportMixin, AbstractPlayer): """ A dummy iTunes Player that allows us to test if files :meth:`can_play`. """ name = u'itunes' """A unicode string identifier for this class.""" display_name = N_(u'iTunes Player') """A unicode display name for the class, to be used in the settings UI.""" supported_containers = set(['mp3', 'mp4']) supported_schemes = set([HTTP])
class DailyMotionStorage(EmbedStorageEngine): engine_type = u'DailyMotionStorage' """A uniquely identifying unicode string for the StorageEngine.""" default_name = N_(u'Daily Motion') url_pattern = re.compile( r'^(http(s?)://)?(\w+\.)?dailymotion.(\w+.?\w*)/video/(?P<id>[^_\?&#]+)_' ) """A compiled pattern object that uses named groupings for matches.""" def _parse(self, url, **kwargs): """Return metadata for the given URL that matches :attr:`url_pattern`. :type url: unicode :param url: A remote URL string. :param \*\*kwargs: The named matches from the url match object. :rtype: dict :returns: Any extracted metadata. """ id = kwargs['id'] # Ensure the video uses the .com TLD for the API request. url = 'http://www.dailymotion.com/video/%s' % id data_url = 'http://www.dailymotion.com/services/oembed?' + \ urlencode({'format': 'json', 'url': url}) headers = {'User-Agent': USER_AGENT} req = Request(data_url, headers=headers) try: temp_data = urlopen(req) try: data_string = temp_data.read() if data_string == 'This video cannot be embeded.': raise UserStorageError( _('This DailyMotion video does not allow embedding.')) data = simplejson.loads(data_string) finally: temp_data.close() except URLError, e: log.exception(e) data = {} return { 'unique_id': id, 'display_name': unicode(data.get('title', u'')), 'thumbnail_url': data.get('thumbnail_url', None), 'type': VIDEO, }
class APIForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.APIForm fields = [ boolean_radiobuttonlist( 'api_secret_key_required', label_text=N_('Require a key to access the API')), ListFieldSet('key', suppress_label=True, legend=N_('API Key:'), css_classes=['details_fieldset'], children=[ TextField('api_secret_key', label_text=N_('Access Key')), ]), ListFieldSet('prefs', suppress_label=True, legend=N_('API Settings:'), css_classes=['details_fieldset'], children=[ TextField('api_media_max_results', label_text=N_('Max media results')), TextField('api_tree_max_depth', label_text=N_('Max tree depth')), ]), SubmitButton('save', default='Save', css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), ]
class TagRowForm(Form): template = 'admin/tags/row-form.html' id = None submit_text = None params = ['tag'] event = events.Admin.TagRowForm fields = [ HiddenField('name'), HiddenField('slug'), SubmitButton('delete', default=N_('Delete'), css_classes=['btn', 'table-row', 'delete', 'btn-inline-delete']), ]
class SearchForm(ListForm): template = 'admin/search-form.html' id = 'nav-search' method = 'get' fields = [ TextField('search', label_text=N_('SEARCH...')), SubmitButton('go', default='Go', css_classes=['clickable nav-search-btn']), ] submit_text = None event = events.Admin.SearchForm