class PodcastForm(ListForm): template = 'admin/box-form.html' id = 'podcast-form' css_class = 'form' submit_text = None event = events.Admin.PodcastForm # required to support multiple named buttons to differentiate between Save & Delete? _name = 'vf' explicit_options = lambda: ( ('no', ''), ('yes', _('Parental Advisory')), ('clean', _('Clean')), ) category_options = [ 'Arts', 'Arts > Design', 'Arts > Fashion & Beauty', 'Arts > Food', 'Arts > Literature', 'Arts > Performing Arts', 'Arts > Visual Arts', 'Business', 'Business > Business News', 'Business > Careers', 'Business > Investing', 'Business > Management & Marketing', 'Business > Shopping', 'Comedy', 'Education', 'Education > Education Technology', 'Education > Higher Education', 'Education > K-12', 'Education > Language Courses', 'Education > Training', 'Games & Hobbies', 'Games & Hobbies > Automotive', 'Games & Hobbies > Aviation', 'Games & Hobbies > Hobbies', 'Games & Hobbies > Other Games', 'Games & Hobbies > Video Games', 'Government & Organizations', 'Government & Organizations > Local', 'Government & Organizations > National', 'Government & Organizations > Non-Profit', 'Government & Organizations > Regional', 'Health', 'Health > Alternative Health', 'Health > Fitness & Nutrition', 'Health > Self-Help', 'Health > Sexuality', 'Kids & Family', 'Music', 'News & Politics', 'Religion & Spirituality', 'Religion & Spirituality > Buddhism', 'Religion & Spirituality > Christianity', 'Religion & Spirituality > Hinduism', 'Religion & Spirituality > Islam', 'Religion & Spirituality > Judaism', 'Religion & Spirituality > Other', 'Religion & Spirituality > Spirituality', 'Science & Medicine', 'Science & Medicine > Medicine', 'Science & Medicine > Natural Sciences', 'Science & Medicine > Social Sciences', 'Society & Culture', 'Society & Culture > History', 'Society & Culture > Personal Journals', 'Society & Culture > Philosophy', 'Society & Culture > Places & Travel', 'Sports & Recreation', 'Sports & Recreation > Amateur', 'Sports & Recreation > College & High School', 'Sports & Recreation > Outdoor', 'Sports & Recreation > Professional', 'Technology', 'Technology > Gadgets', 'Technology > Tech News', 'Technology > Podcasting', 'Technology > Software How-To', 'TV & Film', ] fields = [ TextField('slug', label_text=N_('Permalink'), validator=NotEmpty, maxlength=50), TextField('title', label_text=N_('Title'), validator=TextField.validator(not_empty=True), maxlength=50), TextField('subtitle', label_text=N_('Subtitle'), maxlength=255), XHTMLTextArea('description', label_text=N_('Description'), attrs=dict(rows=5, cols=25)), ListFieldSet('details', suppress_label=True, legend=N_('Podcast Details:'), css_classes=['details_fieldset'], children=[ SingleSelectField('explicit', label_text=N_('Explicit?'), options=explicit_options), SingleSelectField('category', label_text=N_('Category'), options=category_options), TextField('copyright', label_text=N_('Copyright'), maxlength=50), ]), ListFieldSet('feed', suppress_label=True, legend=N_('Advanced Options:'), css_classes=['details_fieldset'], template='/admin/podcasts/feed_fieldset.html', children=[ TextField('feed_url', maxlength=50, label_text=N_('Your Feed URL'), attrs={'readonly': True}), TextField('itunes_url', validator=URL, label_text=N_('iTunes URL'), maxlength=80), TextField('feedburner_url', validator=URL, label_text=N_('Feedburner URL'), maxlength=80), ]), SubmitButton('save', default=N_('Save'), named_button=True, css_classes=['btn', 'blue', 'f-rgt']), SubmitButton('delete', default=N_('Delete'), named_button=True, css_classes=['btn']), ]
# See LICENSE.txt in the main project directory, for more information. from tw.api import WidgetsList from tw.forms.validators import FieldStorageUploadConverter from mediadrop.lib.i18n import N_ from mediadrop.forms import ListForm, TextField, XHTMLTextArea, FileField, SubmitButton, email_validator from mediadrop.plugin import events validators = dict( description = XHTMLTextArea.validator( messages = {'empty': N_('At least give it a short description...')}, not_empty = True, ), name = TextField.validator( messages = {'empty': N_("You've gotta have a name!")}, not_empty = True, ), title = TextField.validator( messages = {'empty': N_("You've gotta have a title!")}, not_empty = True, ), url = TextField.validator( if_missing = None, ), ) class UploadForm(ListForm): template = 'upload/form.html' id = 'upload-form' css_class = 'form' show_children_errors = False
class AppearanceForm(ListForm): template = 'admin/box-form.html' id = 'settings-form' css_class = 'form' submit_text = None event = events.Admin.Settings.AppearanceForm fields = [ ListFieldSet('general', suppress_label=True, legend=N_('General'), css_classes=['details_fieldset'], children=[ FileField('appearance_logo', label_text=N_('Logo'), validator=FieldStorageUploadConverter(not_empty=False, label_text=N_('Upload Logo')), css_classes=[], default=lambda: request.settings.get('appearance_logo', \ 'logo.png'), template='./admin/settings/appearance_input_field.html'), FileField('appearance_background_image', label_text=N_('Background Image'), validator=FieldStorageUploadConverter(not_empty=False, label_text=N_('Upload Background')), css_classes=[], default=lambda: request.settings.get('appearance_background_image', \ 'bg_image.png'), template='./admin/settings/appearance_input_field.html'), TextField('appearance_background_color', maxlength=255, label_text=N_('Background color'), validator=Regex(hex_validation_regex, strip=True)), TextField('appearance_link_color', maxlength=255, label_text=N_('Link color'), validator=Regex(hex_validation_regex, strip=True)), TextField('appearance_visited_link_color', maxlength=255, label_text=N_('Visited Link color'), validator=Regex(hex_validation_regex, strip=True)), TextField('appearance_text_color', maxlength=255, validator=Regex(hex_validation_regex, strip=True), label_text=N_('Text color')), TextField('appearance_heading_color', maxlength=255, label_text=N_('Heading color'), validator=Regex(hex_validation_regex, strip=True)), SingleSelectField('appearance_navigation_bar_color', label_text=N_('Color Scheme'), options=navbar_colors), ] ), ListFieldSet('options', suppress_label=True, legend=N_('Options'), css_classes=['details_fieldset'], children=[ CheckBox('appearance_enable_cooliris', css_classes=['checkbox-left'], label_text=N_('Enable Cooliris on the Explore Page'), help_text=N_('Cooliris support is deprecated and will be ' + \ 'removed in the next major version of MediaDrop ' + \ 'unless someone is interested in maintaining it.'), validator=Bool(if_missing='')), CheckBox(u'appearance_display_login', css_classes=['checkbox-left'], label_text=N_('Display login link for all users'), validator=Bool(if_missing='')), CheckBox('appearance_enable_featured_items', label_text=N_('Enable Featured Items on the Explore Page'), css_classes=['checkbox-left'], validator=Bool(if_missing='')), CheckBox('appearance_enable_podcast_tab', label_text=N_('Enable Podcast Tab'), css_classes=['checkbox-left'], validator=Bool(if_missing='')), CheckBox('appearance_enable_user_uploads', label_text=N_('Enable User Uploads'), css_classes=['checkbox-left'], validator=Bool(if_missing='')), CheckBox('appearance_enable_widescreen_view', label_text=N_('Enable widescreen media player by default'), css_classes=['checkbox-left'], validator=Bool(if_missing='')), CheckBox('appearance_display_logo', label_text=N_('Display Logo'), css_classes=['checkbox-left'], validator=Bool(if_missing='')), CheckBox('appearance_display_background_image', label_text=N_('Display Background Image'), css_classes=['checkbox-left'], validator=Bool(if_missing='')), CheckBox('appearance_display_mediadrop_footer', label_text=N_('Display MediaDrop Footer'), css_classes=['checkbox-left'], validator=Bool(if_missing='')), CheckBox('appearance_display_mediadrop_credits', label_text=N_('Display MediaDrop Credits in Footer'), css_classes=['checkbox-left'], validator=Bool(if_missing='')), ], template='./admin/settings/appearance_list_fieldset.html', ), ListFieldSet('player', suppress_label=True, legend=N_('Player Menu Options'), css_classes=['details_fieldset'], children=[ CheckBox('appearance_show_download', css_classes=['checkbox-left'], label_text=N_('Enable Download button on player menu bar.'), validator=Bool(if_missing='')), CheckBox('appearance_show_share', css_classes=['checkbox-left'], label_text=N_('Enable Share button on player menu bar.'), validator=Bool(if_missing='')), CheckBox('appearance_show_embed', css_classes=['checkbox-left'], label_text=N_('Enable Embed button on player menu bar.'), validator=Bool(if_missing='')), CheckBox('appearance_show_widescreen', css_classes=['checkbox-left'], label_text=N_('Enable Widescreen toggle button on player menu bar.'), validator=Bool(if_missing='')), CheckBox('appearance_show_popout', css_classes=['checkbox-left'], label_text=N_('Enable Popout button on player menu bar.'), validator=Bool(if_missing='')), CheckBox('appearance_show_like', css_classes=['checkbox-left'], label_text=N_('Enable Like button on player menu bar.'), validator=Bool(if_missing='')), CheckBox('appearance_show_dislike', css_classes=['checkbox-left'], label_text=N_('Enable Dislike button on player menu bar.'), validator=Bool(if_missing='')), ], template='./admin/settings/appearance_list_fieldset.html', ), ListFieldSet('advanced', suppress_label=True, legend=N_('Advanced'), css_classes=['details_fieldset'], children=[ TextArea('appearance_custom_css', label_text=N_('Custom CSS'), attrs=dict(rows=15, cols=25)), TextArea('appearance_custom_header_html', label_text=N_('Custom Header HTML'), attrs=dict(rows=15, cols=25)), TextArea('appearance_custom_footer_html', label_text=N_('Custom Footer HTML'), attrs=dict(rows=15, cols=25)), TextArea('appearance_custom_head_tags', label_text=N_('Custom <head> Tags'), help_text=N_('These HTML tags are inserted into the HTML ' '<head> section. Bad input can cause ugly rendering of ' 'your site. You can always restore your page by ' 'the box above.'), attrs=dict(rows=15, cols=25)), ], ), SubmitButton('save', default=N_('Save'), css_classes=['btn', 'btn-save', 'blue', 'f-rgt']), SubmitButton('reset', default=N_('Reset to Defaults'), css_classes=['btn', 'btn-cancel', 'reset-confirm']), ]
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 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 StorageForm(ListForm): template = 'admin/box-form.html' id = 'storage-form' css_class = 'form storageform' submit_text = None show_children_errors = True _name = 'storage-form' # TODO: Figure out why this is required?? params = ['engine'] 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, 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 """ general = value.setdefault('general', {}) if not general.get('display_name', None): general['display_name'] = engine.display_name return ListForm.display(self, value, engine=engine, **kwargs) def save_engine_params(self, engine, general, **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. """ engine.display_name = general['display_name']
class RemoteURLStorageForm(StorageForm): event = events.Admin.Storage.RemoteURLStorageForm fields = StorageForm.fields + [ ListFieldSet( 'rtmp', legend=N_('RTMP Servers:'), suppress_label=True, children=[ # FIXME: Display errors from the RTMPURLValidator FormFieldRepeater( 'known_servers', widget=TextField( css_classes=['textfield rtmp-server-uri'], validator=RTMPURLValidator(), ), suppress_label=True, repetitions=1, ), ], ) ] + StorageForm.buttons javascript = [rtmp_server_js] 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 """ rtmp = value.setdefault('rtmp', {}) rtmp.setdefault('known_servers', engine._data.get('rtmp_server_uris', ())) 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) rtmp = kwargs.get('rtmp', {}) rtmp_servers = rtmp.get('known_servers', ()) engine._data['rtmp_server_uris'] = [x for x in rtmp_servers if x]
class FTPStorageForm(StorageForm): event = events.Admin.Storage.FTPStorageForm fields = StorageForm.fields + [ ListFieldSet( 'ftp', suppress_label=True, legend=N_('FTP Server Details:'), children=[ TextField('server', label_text=N_('Server Hostname')), TextField('user', label_text=N_('Username')), TextField('password', label_text=N_('Password')), TextField( 'upload_dir', label_text=N_('Subdirectory on server to upload to')), TextField( 'upload_integrity_retries', label_text=N_( 'How many times should MediaDrop try to verify the FTP upload before declaring it a failure?' ), validator=Int()), TextField( 'http_download_uri', label_text=N_('HTTP URL to access remotely stored files')), TextField( 'rtmp_server_uri', label_text=N_( 'RTMP Server URL to stream remotely stored files (Optional)' )), ]), ] + 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 """ data = engine._data ftp = value.setdefault('ftp', {}) ftp.setdefault('server', data.get(FTP_SERVER, None)) ftp.setdefault('user', data.get(FTP_USERNAME, None)) ftp.setdefault('password', data.get(FTP_PASSWORD, None)) ftp.setdefault('upload_dir', data.get(FTP_UPLOAD_DIR, None)) ftp.setdefault('upload_integrity_retries', data.get(FTP_MAX_INTEGRITY_RETRIES, None)) ftp.setdefault('http_download_uri', data.get(HTTP_DOWNLOAD_URI, None)) ftp.setdefault('rtmp_server_uri', 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) ftp = kwargs['ftp'] engine._data[FTP_SERVER] = ftp['server'] engine._data[FTP_USERNAME] = ftp['user'] engine._data[FTP_PASSWORD] = ftp['password'] engine._data[FTP_UPLOAD_DIR] = ftp['upload_dir'] engine._data[FTP_MAX_INTEGRITY_RETRIES] = ftp[ 'upload_integrity_retries'] engine._data[HTTP_DOWNLOAD_URI] = ftp['http_download_uri'] engine._data[RTMP_SERVER_URI] = ftp['rtmp_server_uri']
# See LICENSE.txt in the main project directory, for more information. from tw.api import WidgetsList from tw.forms.validators import FieldStorageUploadConverter from mediadrop.lib.i18n import N_ from mediadrop.forms import ListForm, TextField, XHTMLTextArea, FileField, SubmitButton, email_validator from mediadrop.plugin import events validators = dict( description=XHTMLTextArea.validator( messages={'empty': N_('At least give it a short description...')}, not_empty=True, ), name=TextField.validator( messages={'empty': N_("You've gotta have a name!")}, not_empty=True, ), title=TextField.validator( messages={'empty': N_("You've gotta have a title!")}, not_empty=True, ), url=TextField.validator(if_missing=None, ), ) class UploadForm(ListForm): template = 'upload/form.html' id = 'upload-form' css_class = 'form' show_children_errors = False params = ['async_action']