import re
import json
import logging
from collections import OrderedDict
from ming import schema as S
from ming.orm import FieldProperty, RelationProperty, ForeignIdProperty
from ming.orm.declarative import MappedClass
from ming.utils import LazyProperty
import pylons
pylons.c = pylons.tmpl_context
pylons.g = pylons.app_globals
from pylons import request, c
from allura.lib import plugin
from .session import main_orm_session
from .filesystem import File
log = logging.getLogger(__name__)
class NeighborhoodFile(File):
class __mongometa__:
session = main_orm_session
indexes = [ 'neighborhood_id' ]
neighborhood_id = FieldProperty(S.ObjectId)
re_picker_css_type = re.compile('^/\*(.+)\*/')
re_font_project_title = re.compile('font-family:(.+);\}')
re_color_project_title = re.compile('color:(.+);\}')
re_bgcolor_barontop = re.compile('background\-color:([^;}]+);')
re_bgcolor_titlebar = re.compile('background\-color:([^;}]+);')
re_color_titlebar = re.compile('color:([^;}]+);')
re_icon_theme = re.compile('neo-icon-set-(ffffff|454545)-256x350.png')
class Neighborhood(MappedClass):
'''Provide a grouping of related projects.
url_prefix - location of neighborhood (may include scheme and/or host)
css - block of CSS text to add to all neighborhood pages
'''
class __mongometa__:
session = main_orm_session
name = 'neighborhood'
unique_indexes = [ 'url_prefix' ]
_id = FieldProperty(S.ObjectId)
name = FieldProperty(str)
url_prefix = FieldProperty(str) # e.g. http://adobe.openforge.com/ or projects/
shortname_prefix = FieldProperty(str, if_missing='')
css = FieldProperty(str, if_missing='')
homepage = FieldProperty(str, if_missing='')
redirect = FieldProperty(str, if_missing='')
projects = RelationProperty('Project')
allow_browse = FieldProperty(bool, if_missing=True)
show_title = FieldProperty(bool, if_missing=True)
site_specific_html = FieldProperty(str, if_missing='')
project_template = FieldProperty(str, if_missing='')
tracking_id = FieldProperty(str, if_missing='')
project_list_url = FieldProperty(str, if_missing='')
level = FieldProperty(S.Deprecated)
allow_private = FieldProperty(S.Deprecated)
features = FieldProperty(dict(
private_projects=bool,
max_projects=S.Int,
css=str,
google_analytics=bool))
anchored_tools = FieldProperty(str, if_missing='')
def parent_security_context(self):
return None
@LazyProperty
def neighborhood_project(self):
from .project import Project
return Project.query.get(
neighborhood_id=self._id,
is_nbhd_project=True)
@property
def acl(self):
return self.neighborhood_project.acl
def url(self):
url = self.url_prefix
if url.startswith('//'):
try:
return request.scheme + ':' + url
except TypeError: # pragma no cover
return 'http:' + url
else:
return url
def register_project(self, shortname, user=None, project_name=None, user_project=False, private_project=False, apps=None):
'''Register a new project in the neighborhood. The given user will
become the project's superuser. If no user is specified, c.user is used.
'''
provider = plugin.ProjectRegistrationProvider.get()
if project_name is None:
project_name = shortname
return provider.register_project(
self, shortname, project_name, user or getattr(c, 'user', None), user_project, private_project, apps)
def bind_controller(self, controller):
from allura.controllers.project import NeighborhoodController
controller_attr = self.url_prefix[1:-1]
setattr(controller, controller_attr, NeighborhoodController(self))
def get_custom_css(self):
if self.allow_custom_css:
return self.css
return ""
@property
def has_home_tool(self):
return (self.neighborhood_project
.app_config_by_tool_type('home') is not None)
@property
def icon(self):
return NeighborhoodFile.query.get(neighborhood_id=self._id)
@property
def allow_custom_css(self):
return self.features['css'] == 'custom' or self.features['css'] == 'picker'
def get_project_template(self):
if self.project_template:
return json.loads(self.project_template)
return {}
def get_max_projects(self):
return self.features['max_projects']
def get_css_for_picker(self):
projecttitlefont = {'label': 'Project title, font', 'name': 'projecttitlefont', 'value':'', 'type': 'font'}
projecttitlecolor = {'label': 'Project title, color', 'name': 'projecttitlecolor', 'value':'', 'type': 'color'}
barontop = {'label': 'Bar on top', 'name': 'barontop', 'value': '', 'type': 'color'}
titlebarbackground = {'label': 'Title bar, background', 'name': 'titlebarbackground', 'value': '', 'type': 'color'}
titlebarcolor = {'label': 'Title bar, foreground', 'name': 'titlebarcolor', 'value': '', 'type': 'color',
'additional': """<label>Icons theme:</label> <select name="css-addopt-icon-theme" class="add_opt">
<option value="default">default</option>
<option value="dark"%(titlebarcolor_dark)s>dark</option>
<option value="white"%(titlebarcolor_white)s>white</option>
</select>"""}
titlebarcolor_dark = ''
titlebarcolor_white = ''
if self.css is not None:
for css_line in self.css.split('\n'):
m = re_picker_css_type.search(css_line)
if not m:
continue
css_type = m.group(1)
if css_type == "projecttitlefont":
m = re_font_project_title.search(css_line)
if m:
projecttitlefont['value'] = m.group(1)
elif css_type == "projecttitlecolor":
m = re_color_project_title.search(css_line)
if m:
projecttitlecolor['value'] = m.group(1)
elif css_type == "barontop":
m = re_bgcolor_barontop.search(css_line)
if m:
barontop['value'] = m.group(1)
elif css_type == "titlebarbackground":
m = re_bgcolor_titlebar.search(css_line)
if m:
titlebarbackground['value'] = m.group(1)
elif css_type == "titlebarcolor":
m = re_color_titlebar.search(css_line)
if m:
titlebarcolor['value'] = m.group(1)
m = re_icon_theme.search(css_line)
if m:
icon_theme = m.group(1)
if icon_theme == "ffffff":
titlebarcolor_dark = ' selected="selected"'
elif icon_theme == "454545":
titlebarcolor_white = ' selected="selected"'
titlebarcolor['additional'] = titlebarcolor['additional'] % {'titlebarcolor_dark': titlebarcolor_dark,
'titlebarcolor_white': titlebarcolor_white}
styles_list = []
styles_list.append(projecttitlefont)
styles_list.append(projecttitlecolor)
styles_list.append(barontop)
styles_list.append(titlebarbackground)
styles_list.append(titlebarcolor)
return styles_list
@staticmethod
def compile_css_for_picker(css_form_dict):
# Check css values
for key in css_form_dict.keys():
if ';' in css_form_dict[key] or '}' in css_form_dict[key]:
css_form_dict[key] = ''
css_text = ""
if 'projecttitlefont' in css_form_dict and css_form_dict['projecttitlefont'] != '':
css_text += "/*projecttitlefont*/.project_title{font-family:%s;}\n" % (css_form_dict['projecttitlefont'])
if 'projecttitlecolor' in css_form_dict and css_form_dict['projecttitlecolor'] != '':
css_text += "/*projecttitlecolor*/.project_title{color:%s;}\n" % (css_form_dict['projecttitlecolor'])
if 'barontop' in css_form_dict and css_form_dict['barontop'] != '':
css_text += "/*barontop*/.pad h2.colored {background-color:%(bgcolor)s; background-image: none;}\n" % \
{'bgcolor': css_form_dict['barontop']}
if 'titlebarbackground' in css_form_dict and css_form_dict['titlebarbackground'] != '':
css_text += "/*titlebarbackground*/.pad h2.title{background-color:%(bgcolor)s; background-image: none;}\n" % \
{'bgcolor': css_form_dict['titlebarbackground']}
if 'titlebarcolor' in css_form_dict and css_form_dict['titlebarcolor'] != '':
icon_theme = ''
if 'addopt-icon-theme' in css_form_dict:
if css_form_dict['addopt-icon-theme'] == "dark":
icon_theme = ".pad h2.dark small b.ico {background-image: url('%s%s');}" % (
pylons.g.theme_href(''),
'images/neo-icon-set-ffffff-256x350.png')
elif css_form_dict['addopt-icon-theme'] == "white":
icon_theme = ".pad h2.dark small b.ico {background-image: url('%s%s');}" % (
pylons.g.theme_href(''),
'images/neo-icon-set-454545-256x350.png')
css_text += "/*titlebarcolor*/.pad h2.title, .pad h2.title small a {color:%s;} %s\n" % (css_form_dict['titlebarcolor'], icon_theme)
return css_text
def migrate_css_for_picker(self):
self.css = ""
def get_anchored_tools(self):
anchored_tools = self.anchored_tools.replace(' ', '').split(',')
try:
return OrderedDict((tool.split(':')[0].lower(), tool.split(':')[1]) for tool in anchored_tools)
except Exception:
return dict()