class TemplateAPI(object): _community_info = None _recent_items = None _identity = None _isStaff = None _intranets_info = None _current_intranet = None _home_url = None _snippets = None _start_time = int(time.time()) countries = countries _form_field_templates = None def __init__(self, context, request, page_title=None): self.context = context self.request = request self.userid = authenticated_userid(request) self.app_url = app_url = request.application_url self.profile_url = app_url + '/profiles/%s' % self.userid self.here_url = self.context_url = model_url(context, request) self.view_url = model_url(context, request, request.view_name) settings = queryUtility(ISettings) self.js_devel_mode = settings and getattr(settings, 'js_devel_mode', None) self.static_url = '%s/static/%s' % (app_url, _get_static_rev()) # this data will be provided for the client javascript self.karl_client_data = {} # Provide a setting in the INI to fully control the entire URL # to the static. This is when the proxy runs a different port # number, or to "pipeline" resources on a different URL path. full_static_path = getattr(settings, 'full_static_path', False) if full_static_path: if '%d' in full_static_path: # XXX XXX note self._start_time is needed... and not _start_time # XXX XXX since this was a trivial bug, there is chance that # XXX XXX this actually never runs! TODO testing??? full_static_path = full_static_path % self._start_time self.static_url = full_static_path self.page_title = page_title self.system_name = get_setting(context, 'system_name', 'KARL') self.user_is_admin = 'group.KarlAdmin' in effective_principals(request) self.site = find_site(context) self.admin_url = model_url(self.site, request, 'admin.html') # XXX XXX XXX This will never work from peoples formish templates # XXX XXX XXX (edit_profile and derivates) because, in those form # XXX XXX XXX controllers, the api is instantiated from __init__, # XXX XXX XXX where request.form is still unset!!! (From all other # XXX XXX XXX formcontrollers the api is instantiated from __call__, # XXX XXX XXX which is why this works. A chicken-and-egg problem, really. if hasattr(request, 'form') and getattr(request.form, 'errors', False): # This is a failed form submission request, specify an error message self.error_message = u'Please correct the indicated errors.' if settings: self.kaltura_info = dict( enabled = getattr(settings, 'kaltura_enabled', False) in ('true', 'True'), partner_id = getattr(settings, 'kaltura_partner_id', ''), sub_partner_id = getattr(settings, 'kaltura_sub_partner_id', ''), admin_secret = getattr(settings, 'kaltura_admin_secret', ''), user_secret = getattr(settings, 'kaltura_user_secret', ''), kcw_uiconf_id = getattr(settings, 'kaltura_kcw_uiconf_id', '1000741'), player_uiconf_id = getattr(settings, 'kaltura_player_uiconf_id', ''), player_cache_st = getattr(settings, 'kaltura_player_cache_st', ''), local_user = self.userid, ) if not getattr(settings, 'kaltura_client_session', False) in ('true', 'True'): # Secrets will not be sent to client, instead session is handled on the server. self.kaltura_info['session_url'] = app_url + '/' + 'kaltura_create_session.json' else: self.kaltura_info = dict( enabled = False, ) # propagate the head data to the client d = self.karl_client_data['kaltura'] = dict(self.kaltura_info) # remove secrets if needed if 'session_url' in d: # server side session management, do not send secrets to client del d['user_secret'] del d['admin_secret'] # from openideo self.formerrors = {} self.formdata = request.POST self.app_config = settings self.rdbstore = RDBMSStore() @property def site_announcement(self): site_announcement = getattr(self.site, 'site_announcement', None) if site_announcement: site_announcement['profile'] = self.find_profile( site_announcement.get('userid', None)) if site_announcement['profile']: return site_announcement return {} def topics(self, context): topics = get_setting(context, 'topics') return sorted(elem.strip() for elem in topics.split('\n') if elem) @property def snippets(self): if self._snippets is None: self._snippets = get_template('templates/snippets.pt') self._snippets.doctype = xhtml return self._snippets def has_staff_acl(self, context): return getattr(context, 'security_state', 'inherits') == 'public' def is_private_in_public_community(self, context): """Return true if the object is private, yet located in a public community. """ if self.community_info is None: return False community = self.community_info.context if context is community: return False if getattr(community, 'security_state', 'inherits') == 'public': return getattr(context, 'security_state', 'inherits') == 'private' return False @property def user_is_staff(self): gn = 'group.KarlStaff' if self._identity is None: self._identity = self.request.environ.get('repoze.who.identity') if self._identity: self._isStaff = gn in self._identity.get('groups', []) return self._isStaff def __getitem__(self, key): if key == 'form_field_templates': # Allow this, for ZPT's sake! return self.form_field_templates raise ValueError, "ZPT attempted to fetch %s" % key @property def community_info(self): if self._community_info is None: community = find_interface(self.context, ICommunity) if community is not None: self._community_info = getMultiAdapter( (community, self.request), ICommunityInfo) return self._community_info @property def recent_items(self): if self._recent_items is None: community = find_interface(self.context, ICommunity) if community is not None: community_path = model_path(community) search = getAdapter(self.context, ICatalogSearch) principals = effective_principals(self.request) self._recent_items = [] num, docids, resolver = search( limit=10, path={'query': community_path}, allowed={'query': principals, 'operator': 'or'}, sort_index='modified_date', reverse=True, interfaces=[ICommunityContent], ) models = filter(None, map(resolver, docids)) for model in models: adapted = getMultiAdapter((model, self.request), IGridEntryInfo) self._recent_items.append(adapted) return self._recent_items community_layout_fn = 'opencore.views:templates/community_layout.pt' @property def community_layout(self): macro_template = get_template(self.community_layout_fn) return macro_template anonymous_layout_fn = 'opencore.views:templates/anonymous_layout.pt' @property def anonymous_layout(self): macro_template = get_template(self.anonymous_layout_fn) return macro_template generic_layout_fn = 'opencore.views:templates/generic_layout.pt' @property def generic_layout(self): macro_template = get_template(self.generic_layout_fn) return macro_template formfields_fn = 'opencore.views:templates/formfields.pt' @property def formfields(self): macro_template = get_template(self.formfields_fn) return macro_template lightbox_layout_fn = 'opencore.views:templates/lightbox_layout.pt' @property def lightbox_layout(self): macro_template = get_template(self.lightbox_layout_fn) return macro_template @property def form_field_templates(self): if self._form_field_templates is None: # calculate and cache value if hasattr(self.request, 'form'): self._form_field_templates = [field.widget.template for field in self.request.form.allfields] else: self._form_field_templates = [] return self._form_field_templates _status_message = None def get_status_message(self): if self._status_message: return self._status_message return self.request.params.get("status_message", None) def set_status_message(self, value): self._status_message = value status_message = property(get_status_message, set_status_message) _error_message = None def get_error_message(self): if self._error_message: return self._error_message return self.request.params.get("error_message", None) def set_error_message(self, value): self._error_message = value error_message = property(get_error_message, set_error_message) @property def people_url(self): # Get a setting for what part is appended the the app_url for # this installation's people directory application. people_path = get_setting(self.context, 'people_path', 'people') return self.app_url + "/" + people_path @property def communities_name(self): from opencore.utils import find_site return find_site(self.context).communities_name @property def tag_users(self): """Data for the tagbox display""" tagquery = getMultiAdapter((self.context, self.request), ITagQuery) return tagquery.tagusers def actions_to_menu(self, actions): """A helper used by the snippets rendering the actions menu. This method converts the flat list of action tuples, passed in as input parameters, into a structured list. From this input:: ( ('Manage Members', 'manage.html'), ('Add Folder', 'add_folder.html'), ('Add File', 'add_file.html'), ('Add Forum', 'add_forum.html'), ) it will generate a submenu structure:: ( ('Manage Members', 'manage.html'), ('Add', '#', ( ('Folder', 'add_folder.html'), ('File', 'add_file.html'), ('Forum', 'add_forum.html'), ) ) but if there are only 2 or less groupable items, the menu stays flat and a submenu is not created. At the moment, there is no information marking the Add items. Therefore the following heuristics is applied: - if a title starts with Add, it is considered as Add item - the rest of the title is considered the content type. XXX p.s. according to this heuristics, the following will also be detected as an Add item:: ('Add Existing', 'add_existing.html') Which won't be a problem if there is no more then 3 Add items altogether. """ result = [] lookahead = [] def process_lookahead(result=result, lookahead=lookahead): if len(lookahead) > 2: # Convert to submenu # take part after "Add " as title. result.append(('Add', '#', [(item[0][4:], item[1]) for item in lookahead])) else: # add to menu as flat result.extend(lookahead) # We processed it del lookahead[:] for action in actions: # Is this a menu action? is_menu_action = action[0].startswith('Add ') # pad them out to make sure template does not fail action = action + ((), ) if is_menu_action: lookahead.append(action) else: # process lookahead process_lookahead() result.append(action) process_lookahead() return result def render_sidebar(self): """Render the sidebar appropriate for the context.""" for ancestor in lineage(self.context): r = queryMultiAdapter((ancestor, self.request), ISidebar) if r is not None: return r(self) # no sidebar exists for this context. return '' def render_footer(self): """Render the footer appropriate for the context.""" for ancestor in lineage(self.context): r = queryMultiAdapter((ancestor, self.request), IFooter,) if r is not None: return r(self) # no footer exists for this context, use the default. return DefaultFooter(self.context, self.request)(self) @property def home_url(self): if self._home_url is None: target, extra_path = get_user_home(self.context, self.request) self._home_url = model_url(target, self.request, *extra_path) return self._home_url @property def settings(self): return SettingsReader(self.context) @property def support_attachments(self): return support_attachments(self.context) @property def logo_url(self): logo_path = get_setting(self.context, 'logo_path', 'images/logo.gif') return '%s/%s' % (self.static_url, logo_path) def render_karl_client_data(self, update_dict=None): """ How to provide data to the client? There are 3 ways: 1. specify the data via the template api api.karl_client_data['my_widget'] = {...my_data...} The code will be injected to all pages automatically. Be careful not to overwrite api.karl_client_data, only update one or more fields of the dictionary. 2. Pass the data directly to the template render_template_to_response(... ... karl_client_data = {'my_widget': {...my_data...}}, ...) The passed dictionary will update the one specified via the template api. 3. Legacy way: head_data from karl.views.utils import convert_to_script render_template_to_response(... ... head_data = convert_to_script({'my_widget': {...my_data...}), ...) Data inserted this way is supported in order to not break old code, but for new code please prefer to use the methods described in point 1. or 2. """ d = dict(self.karl_client_data) if update_dict: d.update(update_dict) return convert_to_script(d, var_name='karl_client_data') def supported_comment_interfaces(self): return (IBlogEntry, ICommunity, IForumTopic, IProfile) def view_count(self, context): return self.rdbstore.view_count(path=model_path(context,''))[0][0] def like_count(self, context): count = 0 if 'likes' in context.__dict__: count = context.likes.count() return count # openideo additions below def get_user_bookmarks(self, filter_challenge=True): if self.userid is None: return [] return get_user_bookmarks(self.context, self.userid, filter_challenge) def render_form_widget(self, widget_id, id, label, choices=[], compulsory=False, default=None, description=None, disabled=False, alt=False): if default is None: default = self.formdata.get(id, '') error = self.formerrors.get(id, '') if isinstance(error, (list, tuple)): error = '\n'.join(error) from repoze.bfg.chameleon_zpt import get_template #template = template_cache.get('form_widgets', createfunc=get_form_widgets) template = get_template('templates/form_widgets.pt') if isinstance(default, (list, tuple)): default_list = default else: default_list = [default] return template.render_macro(widget_id, global_scope=True, parameters=dict(name=id, label=label, description=description, choices=choices, compulsory=compulsory, default_value=default, default_list=default_list, error=error, disabled=disabled, alt=alt, api=self,)) def model_path(self, obj): return model_path(obj) def find_model(self, path): return find_model(self.context, path) def get_url(self, ob): """ Returns the model url for `ob` """ return model_url(ob, self.request).replace('https://', 'http://') def find_profile(self, uid): profiles = find_profiles(self.context) return profiles.get(uid, None) def find_image_url(self, ob, search='photo', default='/img/default_user.png', size=None): if ob is None: return default photo = find_image(ob, search) if photo is not None: if isinstance(photo, (unicode, str)): # external reference thumbnail_url return photo if size: return thumb_url(photo, self.request, size) else: return model_url(photo, self.request, 'dl') else: if default.startswith('/'): # absolute local url default = self.static_url + default return default def get_interfaces(self, ob): return [i.__name__ for i in providedBy(ob)] def time_ago(self, time): """ time difference """ now = datetime.now() delta = (now - time) if( delta.days == 1 ) : return '%d day' % delta.days elif( delta.days > 0 ) : return '%d days' % delta.days elif ( (delta.seconds/3600) > 1 ) : return '%d hours' % (delta.seconds/3600) elif ( (delta.seconds/60) > 1 ) : return '%d mins' % (delta.seconds/60) else : return 'Moments' def format_date(self, d, with_break=False, time_less=False): if with_break and not time_less: return d.strftime('%B %d, %Y<br /> %I:%M%p') elif not time_less: return d.strftime('%B %d, %Y, %I:%M%p') else: return d.strftime('%B %d, %Y') def thumb_url(self, image, size=(200, 200)): return thumb_url(image, self.request, size)
def __init__(self, context, request, page_title=None): self.context = context self.request = request self.userid = authenticated_userid(request) self.app_url = app_url = request.application_url self.profile_url = app_url + '/profiles/%s' % self.userid self.here_url = self.context_url = model_url(context, request) self.view_url = model_url(context, request, request.view_name) settings = queryUtility(ISettings) self.js_devel_mode = settings and getattr(settings, 'js_devel_mode', None) self.static_url = '%s/static/%s' % (app_url, _get_static_rev()) # this data will be provided for the client javascript self.karl_client_data = {} # Provide a setting in the INI to fully control the entire URL # to the static. This is when the proxy runs a different port # number, or to "pipeline" resources on a different URL path. full_static_path = getattr(settings, 'full_static_path', False) if full_static_path: if '%d' in full_static_path: # XXX XXX note self._start_time is needed... and not _start_time # XXX XXX since this was a trivial bug, there is chance that # XXX XXX this actually never runs! TODO testing??? full_static_path = full_static_path % self._start_time self.static_url = full_static_path self.page_title = page_title self.system_name = get_setting(context, 'system_name', 'KARL') self.user_is_admin = 'group.KarlAdmin' in effective_principals(request) self.site = find_site(context) self.admin_url = model_url(self.site, request, 'admin.html') # XXX XXX XXX This will never work from peoples formish templates # XXX XXX XXX (edit_profile and derivates) because, in those form # XXX XXX XXX controllers, the api is instantiated from __init__, # XXX XXX XXX where request.form is still unset!!! (From all other # XXX XXX XXX formcontrollers the api is instantiated from __call__, # XXX XXX XXX which is why this works. A chicken-and-egg problem, really. if hasattr(request, 'form') and getattr(request.form, 'errors', False): # This is a failed form submission request, specify an error message self.error_message = u'Please correct the indicated errors.' if settings: self.kaltura_info = dict( enabled = getattr(settings, 'kaltura_enabled', False) in ('true', 'True'), partner_id = getattr(settings, 'kaltura_partner_id', ''), sub_partner_id = getattr(settings, 'kaltura_sub_partner_id', ''), admin_secret = getattr(settings, 'kaltura_admin_secret', ''), user_secret = getattr(settings, 'kaltura_user_secret', ''), kcw_uiconf_id = getattr(settings, 'kaltura_kcw_uiconf_id', '1000741'), player_uiconf_id = getattr(settings, 'kaltura_player_uiconf_id', ''), player_cache_st = getattr(settings, 'kaltura_player_cache_st', ''), local_user = self.userid, ) if not getattr(settings, 'kaltura_client_session', False) in ('true', 'True'): # Secrets will not be sent to client, instead session is handled on the server. self.kaltura_info['session_url'] = app_url + '/' + 'kaltura_create_session.json' else: self.kaltura_info = dict( enabled = False, ) # propagate the head data to the client d = self.karl_client_data['kaltura'] = dict(self.kaltura_info) # remove secrets if needed if 'session_url' in d: # server side session management, do not send secrets to client del d['user_secret'] del d['admin_secret'] # from openideo self.formerrors = {} self.formdata = request.POST self.app_config = settings self.rdbstore = RDBMSStore()