Exemplo n.º 1
0
 def fields(self):
     username = ew.TextField(
         name='username',
         label='Desired Username',
         validator=plugin.AuthenticationProvider.get(
             None).username_validator(),
     )
     fields = [
         ew.TextField(name='display_name',
                      label='Displayed Name',
                      validator=V.UnicodeString(not_empty=True)),
         username,
     ]
     if asbool(config.get('auth.require_email_addr', False)):
         fields.append(
             ew.TextField(name='email',
                          label='Your e-mail',
                          validator=fev.Email(not_empty=True)))
     fields += [
         ew.PasswordField(
             name='pw',
             label='New Password',
             attrs=dict(
                 minlength=asint(tg.config.get('auth.min_password_len', 6)),
                 maxlength=asint(tg.config.get('auth.max_password_len',
                                               30))),
             validator=V.UnicodeString(
                 not_empty=True,
                 min=asint(tg.config.get('auth.min_password_len', 6)),
                 max=asint(tg.config.get('auth.max_password_len', 30)))),
         ew.PasswordField(name='pw2',
                          label='New Password (again)',
                          validator=V.UnicodeString(not_empty=True)),
     ]
     return fields
Exemplo n.º 2
0
 def fields(self):
     return [
         ew.PasswordField(
             name='oldpw',
             label='Old Password',
             validator=V.UnicodeString(not_empty=True),
             attrs=dict(
                 required=True,
                 autocomplete='current-password',
             ),
         ),
         ew.PasswordField(
             name='pw',
             label='New Password',
             attrs=dict(
                 minlength=asint(tg.config.get('auth.min_password_len', 6)),
                 maxlength=asint(tg.config.get('auth.max_password_len', 30)),
                 required=True,
                 autocomplete='new-password',
             ),
             validator=V.UnicodeString(
                 not_empty=True,
                 min=asint(tg.config.get('auth.min_password_len', 6)),
                 max=asint(tg.config.get('auth.max_password_len', 30)))),
         ew.PasswordField(
             name='pw2',
             label='New Password (again)',
             validator=V.UnicodeString(not_empty=True),
             attrs=dict(
                 required=True,
                 autocomplete='new-password',
             ),
         ),
         ew.HiddenField(name='return_to'),
     ]
Exemplo n.º 3
0
 class fields(ew_core.NameList):
     uppercategory_id = ew.HiddenField(attrs={'value': ''},
                                       show_errors=False)
     categoryname = ew.TextField(label="Category name",
                                 attrs={},
                                 validator=V.UnicodeString(not_empty=True))
     shortname = ew.TextField(
         label="Short name",
         validator=V.UnicodeString(),
         attrs={'placeholder': 'optional; unique identifier'})
Exemplo n.º 4
0
 class fields(ew_core.NameList):
     startdate = ew.TextField(
         label='Start date',
         validator=formencode.All(
             V.DateValidator(),
             V.UnicodeString(not_empty=True)))
     enddate = ew.TextField(
         label='End date',
         validator=formencode.All(
             V.DateValidator(),
             V.UnicodeString(not_empty=True)))
Exemplo n.º 5
0
    def fields(self):
        provider = plugin.ProjectRegistrationProvider.get()
        tools_options = []
        for ep, tool in six.iteritems(g.entry_points["tool"]):
            if tool.status == 'production' and tool._installable(tool_name=ep,
                                                                 nbhd=c.project.neighborhood,
                                                                 project_tools=[]):
                tools_options.append(ew.Option(label=tool.tool_label, html_value=ep))

        return ew_core.NameList([
            ew.HiddenField(name='project_description', label='Public Description'),
            ew.HiddenField(name='neighborhood', label='Neighborhood'),
            ew.Checkbox(name='private_project', label="", attrs={'class': 'unlabeled'}),
            ew.InputField(name='project_name', label='Project Name',
                          field_type='text',
                          validator=formencode.All(
                              V.UnicodeString(not_empty=True, max=40),
                              V.MaxBytesValidator(max=40)),
                          ),
            ew.InputField(name='project_unixname',
                          label='Short Name', field_type='text',
                          attrs={
                              'title': 'Create a URL name that matches your project name as closely as possible to improve search indexing and maximize visibility.',
                              'class': 'tooltip'
                          },
                          validator=provider.shortname_validator),
            ew.CheckboxSet(name='tools', options=tools_options),
        ])
Exemplo n.º 6
0
 def fields(self):
     return ew_core.NameList([
         ew.TextField(name='title',
                      validator=v.UnicodeString(
                          not_empty=True,
                          messages={'empty': "You must provide a Title"}),
                      attrs=dict(placeholder='Enter your title here',
                                 title='Enter your title here',
                                 style='width: 425px')),
         ffw.MarkdownEdit(name='text',
                          show_label=False,
                          attrs=dict(placeholder='Enter your content here',
                                     title='Enter your content here')),
         ew.SingleSelectField(name='state',
                              options=[
                                  ew.Option(py_value='draft',
                                            label='Draft'),
                                  ew.Option(py_value='published',
                                            label='Published')
                              ]),
         ffw.LabelEdit(name='labels',
                       placeholder='Add labels here',
                       title='Add labels here'),
         ew.InputField(
             name='attachment',
             label='Attachment',
             field_type='file',
             attrs={'multiple': 'True'},
             validator=fev.FieldStorageUploadConverter(if_missing=None)),
     ])
Exemplo n.º 7
0
 def fields(self):
     socialnetworks = aslist(tg.config.get('socialnetworks',
                                           ['Facebook', 'Linkedin', 'Twitter', 'Google+']),
                             ',')
     return [
         ew.SingleSelectField(
             name='socialnetwork',
             label='Social network',
             validator=V.UnicodeString(not_empty=True),
             options=[ew.Option(py_value=name, label=name)
                      for name in socialnetworks]),
         ew.TextField(
             name='accounturl',
             label='Account url',
             validator=V.UnicodeString(not_empty=True))
     ]
Exemplo n.º 8
0
    class fields(ew_core.NameList):
        subject = ew.TextField(validator=v.UnicodeString(
            not_empty=True, messages={'empty': "You must provide a Subject"}),
                               attrs=dict(
                                   placeholder='Enter your subject here',
                                   title='Enter your subject here',
                                   style='width: 425px'),
                               label='Subject')

        message = ew.TextArea(validator=v.UnicodeString(
            not_empty=True, messages={'empty': "You must provide a Message"}),
                              attrs=dict(placeholder='Enter your message here',
                                         title='Enter your message here',
                                         style='width: 425px; height:200px'),
                              label='Message')

        cc = ew.Checkbox(label='Send me a copy')
Exemplo n.º 9
0
 class fields(ew_core.NameList):
     selected_skill = ew.HiddenField(
         attrs={'value': ''},
         show_errors=False,
         validator=V.UnicodeString(not_empty=True))
     level = ew.SingleSelectField(
         label="Level of knowledge",
         options=[
             ew.Option(py_value="low", label="Low level"),
             ew.Option(py_value="medium", label="Medium level"),
             ew.Option(py_value="high", label="Advanced level")],
         validator=formencode.All(
             V.OneOfValidator(['low', 'medium', 'high']),
             V.UnicodeString(not_empty=True)))
     comment = ew.TextArea(
         label="Additional comments",
         validator=V.UnicodeString(not_empty=False),
         attrs={'rows': 5, 'cols': 30})
Exemplo n.º 10
0
 class fields(ew_core.NameList):
     weekday = ew.SingleSelectField(
         label='Weekday',
         options=[ew.Option(py_value=wd, label=wd)
                  for wd in weekdays],
         validator=formencode.All(
             V.OneOfValidator(weekdays),
             V.UnicodeString(not_empty=True)))
     starttime = ew.TextField(
         label='Start time',
         validator=formencode.All(
             V.TimeValidator(),
             V.UnicodeString(not_empty=True)))
     endtime = ew.TextField(
         label='End time',
         validator=formencode.All(
             V.TimeValidator(),
             V.UnicodeString(not_empty=True)))
Exemplo n.º 11
0
    def display(self, **kw):
        categories = kw.get('categories')

        self.fields['selected_category'].options = [
            ew.Option(py_value=el.trove_cat_id, label=el.fullname) for el in categories
        ]
        self.fields['selected_category'].validator = formencode.All(
            V.OneOfValidator(categories),
            V.UnicodeString(not_empty=True))
        return super(ForgeForm, self).display(**kw)
Exemplo n.º 12
0
class ProjectImportForm(schema.Schema):
    def __init__(self, source):
        super(ProjectImportForm, self).__init__()
        provider = ProjectRegistrationProvider.get()
        self.add_field('tools', ToolsValidator(source))
        self.add_field('project_shortname', provider.shortname_validator)
        self.allow_extra_fields = True

    neighborhood = fev.NotEmpty()
    project_name = v.UnicodeString(not_empty=True, max=40)
Exemplo n.º 13
0
    def fields(self):
        # Since @property is readonly we can't modify field values in display() method
        # Returns fields modified by display()
        if self._fields:
            return self._fields

        list_of_fields = [
            ew.SingleSelectField(
                name='sex',
                label='Gender',
                options=[ew.Option(py_value=v, label=v, selected=False)
                         for v in ['Male', 'Female', 'Unknown', 'Other']],
                validator=formencode.All(
                    V.OneOfValidator(['Male', 'Female', 'Unknown', 'Other']),
                    V.UnicodeString(not_empty=True))),
            ew.SingleSelectField(
                name='country',
                label='Country of residence',
                validator=V.MapValidator(country_names, not_empty=False),
                options=[ew.Option(py_value=" ", label=" -- Unknown -- ", selected=False)] +
                        [ew.Option(py_value=c, label=n, selected=False)
                         for c, n in sorted(list(country_names.items()),
                                            key=lambda k_v: k_v[1])],
                attrs={'onchange': 'selectTimezone(this.value)'}),
            ew.TextField(
                name='city',
                label='City of residence',
                attrs=dict(value=None),
                validator=V.UnicodeString(not_empty=False)),
            ew.SingleSelectField(
                name='timezone',
                label='Timezone',
                attrs={'id': 'tz'},
                validator=V.OneOfValidator(common_timezones, not_empty=False),
                options=[ew.Option(py_value=" ", label=" -- Unknown -- ")] +
                        [ew.Option(py_value=n, label=n)
                         for n in sorted(common_timezones)])
        ]
        if asbool(tg.config.get('auth.allow_birth_date', True)):
            list_of_fields[1:1] = self.birth_date_fields

        return list_of_fields
Exemplo n.º 14
0
 def fields(self):
     fields = [
         ew.HiddenField(name='app_id', label='App'),
         ew.TextField(name='name', label='Name',
                      validator=v.UnicodeString()),
         ew.TextField(name='shortname', label='Short Name',
                      validator=All(
                          fev.Regex(r"^[^\s\/\.]*$", not_empty=True, messages={
                              'invalid': 'Shortname cannot contain space . or /',
                              'empty': 'You must create a short name for the forum.'}),
                          UniqueForumShortnameValidator())),
         ew.TextField(name='parent', label='Parent Forum'),
         ew.TextField(name='description', label='Description',
                      validator=v.UnicodeString()),
         ew.TextField(name='monitoring_email',
                      label='Monitoring Email', validator=fev.Email()),
         ew.Checkbox(name="members_only", label="Developer Only"),
         ew.Checkbox(name="anon_posts", label="Allow Anonymous Posts")
     ]
     return fields
Exemplo n.º 15
0
 def fields(self):
     return [
         ew.SingleSelectField(name='grant',
                              label='Award',
                              options=self.award_options()),
         ffw.NeighborhoodProjectSelect(self._project_select_url,
                                       name='recipient'),
         ew.TextField(name='url', label='Award URL', validator=fev.URL()),
         ew.TextArea(name='comment',
                     label='Comment',
                     validator=V.UnicodeString(not_empty=False),
                     attrs={
                         'rows': 5,
                         'cols': 30
                     }),
     ]
Exemplo n.º 16
0
 def fields(self):
     fields = ew_core.NameList()
     fields.append(ffw.MarkdownEdit(name='text'))
     fields.append(ew.HiddenField(name='forum', if_missing=None))
     fields.append(ew.Checkbox(name='subscribe', label='Subscribe', if_missing=False))
     if ew_core.widget_context.widget:
         # we are being displayed
         if ew_core.widget_context.render_context.get('show_subject', self.show_subject):
             fields.append(
                 ew.TextField(name='subject', attrs=dict(style="width:97%")))
     else:
         # We are being validated
         validator = v.UnicodeString(not_empty=True, if_missing='')
         fields.append(ew.TextField(name='subject', validator=validator))
         fields.append(NullValidator(name=self.att_name))
     return fields
Exemplo n.º 17
0
class MarkdownEdit(ew.TextArea):
    template = 'jinja:allura:templates/widgets/markdown_edit.html'
    validator = v.UnicodeString()
    defaults = dict(ew.TextArea.defaults,
                    name=None,
                    value=None,
                    show_label=True)

    def from_python(self, value, state=None):
        return value

    def resources(self):
        for r in super(MarkdownEdit, self).resources():
            yield r
        yield ew.JSLink('js/jquery.lightbox_me.js')
        yield ew.CSSLink('css/easymde.min.css', compress=False)
        yield ew.CSSLink('css/markitup_sf.css')
        yield ew.CSSLink('css/show-hint.css')
        yield ew.JSLink('js/easymde.min.js')
        yield ew.JSLink('js/sf_markitup.js')
        yield ew.JSLink('js/show-hint.js')
        yield ew.JSLink('js/usermentions-helper.js')
        yield onready('getProjectUsers(\'%s/users\')' % c.project.url())
Exemplo n.º 18
0
class RootController(BaseController):
    @expose()
    def index(self, **kw):
        now = datetime.utcnow()
        redirect(c.app.url + now.strftime('%Y/%m/%d/'))

    @with_trailing_slash
    @expose('jinja:forgechat:templates/chat/search.html')
    @validate(
        dict(q=v.UnicodeString(if_empty=None),
             project=validators.StringBool(if_empty=False)))
    def search(self, q=None, project=None, limit=None, page=0, **kw):
        c.search_results = SearchResults()
        c.help_modal = SearchHelp(comments=False,
                                  history=False,
                                  fields={
                                      'sender_t': 'username',
                                      'text': '"Message text"',
                                  })
        search_params = kw
        search_params.update({
            'q': q or '',
            'project': project,
            'limit': limit,
            'page': page,
            'allowed_types': ['Chat Message'],
        })
        d = search_app(**search_params)
        d['search_comments_disable'] = True
        d['search_history_disable'] = True
        return d

    @expose()
    def _lookup(self, y, m, d, *rest):
        y, m, d = int(y), int(m), int(d)
        return DayController(date(y, m, d)), rest
Exemplo n.º 19
0
class GitHubRepoImportForm(ToolImportForm):
    gh_user_name = v.UnicodeString(not_empty=True)
    gh_project_name = GitHubProjectNameValidator()
Exemplo n.º 20
0
class DeleteProjectsController(object):
    delete_form_validators = dict(
        projects=v.UnicodeString(if_empty=None),
        reason=v.UnicodeString(if_empty=None),
        disable_users=validators.StringBool(if_empty=False))

    def remove_comments(self, lines):
        return [l.split('#', 1)[0] for l in lines]

    def parse_projects(self, projects):
        """Takes projects from user input and returns a list of tuples (input, project, error)"""
        provider = ProjectRegistrationProvider.get()
        projects = projects.splitlines()
        projects = self.remove_comments(projects)
        parsed_projects = []
        for input in projects:
            if input.strip():
                p, error = provider.project_from_url(input.strip())
                parsed_projects.append((input, p, error))
        return parsed_projects

    def format_parsed_projects(self, projects):
        template = '{}    # {}'
        lines = []
        for input, p, error in projects:
            comment = 'OK: {}'.format(p.url()) if p else error
            lines.append(template.format(input, comment))
        return '\n'.join(lines)

    @with_trailing_slash
    @expose('jinja:allura:templates/site_admin_delete_projects.html')
    @validate(validators=delete_form_validators)
    def index(self, projects=None, reason=None, disable_users=False, **kw):
        return {
            'projects': projects,
            'reason': reason,
            'disable_users': disable_users
        }

    @expose('jinja:allura:templates/site_admin_delete_projects_confirm.html')
    @require_post()
    @without_trailing_slash
    @validate(validators=delete_form_validators)
    def confirm(self, projects=None, reason=None, disable_users=False, **kw):
        if not projects:
            flash('No projects specified', 'warning')
            redirect('.')
        parsed_projects = self.parse_projects(projects)
        projects = self.format_parsed_projects(parsed_projects)
        edit_link = './?projects={}&reason={}&disable_users={}'.format(
            h.urlquoteplus(projects), h.urlquoteplus(reason or ''),
            h.urlquoteplus(disable_users))
        return {
            'projects': projects,
            'parsed_projects': parsed_projects,
            'edit_link': edit_link,
            'reason': reason,
            'disable_users': disable_users
        }

    @expose()
    @require_post()
    @without_trailing_slash
    @validate(validators=delete_form_validators)
    def really_delete(self,
                      projects=None,
                      reason=None,
                      disable_users=False,
                      **kw):
        if not projects:
            flash('No projects specified', 'warning')
            redirect('.')
        projects = self.parse_projects(projects)
        task_params = [p.url().strip('/') for (_, p, _) in projects if p]
        if not task_params:
            flash('Unable to parse at least one project from your input',
                  'warning')
            redirect('.')
        task_params = ' '.join(task_params)
        if reason:
            task_params = '-r {} {}'.format(pipes.quote(reason), task_params)
        if disable_users:
            task_params = '--disable-users {}'.format(task_params)
        DeleteProjects.post(task_params)
        flash('Delete scheduled', 'ok')
        redirect('.')
Exemplo n.º 21
0
class SiteAdminController(object):
    def __init__(self):
        self.task_manager = TaskManagerController()
        self.user = AdminUserDetailsController()
        self.delete_projects = DeleteProjectsController()
        self.site_notifications = SiteNotificationController()

    def _check_security(self):
        require_site_admin(c.user)

        c.site_admin_sidebar_menu = self.sidebar_menu()

    @expose()
    def _lookup(self, name, *remainder):
        for ep_name in sorted(g.entry_points['site_admin'].keys()):
            admin_extension = g.entry_points['site_admin'][ep_name]
            controller = admin_extension().controllers.get(name)
            if controller:
                return controller(), remainder
        raise HTTPNotFound(name)

    def sidebar_menu(self):
        base_url = '/nf/admin/'
        links = [
            SitemapEntry('Home', base_url, ui_icon=g.icons['admin']),
            SitemapEntry('Add Subscribers',
                         base_url + 'add_subscribers',
                         ui_icon=g.icons['admin']),
            SitemapEntry('New Projects',
                         base_url + 'new_projects',
                         ui_icon=g.icons['admin']),
            SitemapEntry('Reclone Repo',
                         base_url + 'reclone_repo',
                         ui_icon=g.icons['admin']),
            SitemapEntry('Task Manager',
                         base_url + 'task_manager?state=busy',
                         ui_icon=g.icons['stats']),
            SitemapEntry('Search Projects',
                         base_url + 'search_projects',
                         ui_icon=g.icons['search']),
            SitemapEntry('Delete Projects',
                         base_url + 'delete_projects',
                         ui_icon=g.icons['delete']),
            SitemapEntry('Search Users',
                         base_url + 'search_users',
                         ui_icon=g.icons['search']),
            SitemapEntry('Site Notifications',
                         base_url + 'site_notifications',
                         ui_icon=g.icons['admin']),
        ]
        for ep_name in sorted(g.entry_points['site_admin']):
            g.entry_points['site_admin'][ep_name]().update_sidebar_menu(links)
        return links

    @expose('jinja:allura:templates/site_admin_index.html')
    @with_trailing_slash
    def index(self, **kw):
        return {}

    def subscribe_artifact(self, url, user):
        artifact_url = urlparse(url).path[1:-1].split("/")
        neighborhood = M.Neighborhood.query.find({
            "url_prefix":
            "/" + artifact_url[0] + "/"
        }).first()

        if artifact_url[0] == "u":
            project = M.Project.query.find({
                "shortname":
                artifact_url[0] + "/" + artifact_url[1],
                "neighborhood_id":
                neighborhood._id
            }).first()
        else:
            project = M.Project.query.find({
                "shortname": artifact_url[1],
                "neighborhood_id": neighborhood._id
            }).first()

        appconf = M.AppConfig.query.find({
            "options.mount_point": artifact_url[2],
            "project_id": project._id
        }).first()

        if appconf.url() == urlparse(url).path:
            M.Mailbox.subscribe(user_id=user._id,
                                app_config_id=appconf._id,
                                project_id=project._id)
            return True

        tool_packages = h.get_tool_packages(appconf.tool_name)
        classes = set()
        for depth, cls in dfs(M.Artifact, build_model_inheritance_graph()):
            for pkg in tool_packages:
                if cls.__module__.startswith(pkg + '.'):
                    classes.add(cls)
        for cls in classes:
            for artifact in cls.query.find({"app_config_id": appconf._id}):
                if artifact.url() == urlparse(url).path:
                    M.Mailbox.subscribe(user_id=user._id,
                                        app_config_id=appconf._id,
                                        project_id=project._id,
                                        artifact=artifact)
                    return True
        return False

    @expose('jinja:allura:templates/site_admin_add_subscribers.html')
    @without_trailing_slash
    def add_subscribers(self, **data):
        if request.method == 'POST':
            url = data['artifact_url']
            user = M.User.by_username(data['for_user'])
            if not user or user == M.User.anonymous():
                flash('Invalid login', 'error')
                return data

            try:
                ok = self.subscribe_artifact(url, user)
            except Exception:
                log.warn("Can't subscribe to artifact", exc_info=True)
                ok = False

            if ok:
                flash('User successfully subscribed to the artifact')
                return {}
            else:
                flash('Artifact not found', 'error')

        return data

    @expose('jinja:allura:templates/site_admin_new_projects.html')
    @without_trailing_slash
    def new_projects(self, **kwargs):
        start_dt = kwargs.pop('start-dt', '')
        end_dt = kwargs.pop('end-dt', '')
        try:
            start_dt = datetime.strptime(start_dt, '%Y/%m/%d %H:%M:%S')
        except ValueError:
            start_dt = datetime.utcnow() + timedelta(days=1)
        try:
            end_dt = datetime.strptime(end_dt, '%Y/%m/%d %H:%M:%S')
        except ValueError:
            end_dt = start_dt - timedelta(days=3) if not end_dt else end_dt
        start = bson.ObjectId.from_datetime(start_dt)
        end = bson.ObjectId.from_datetime(end_dt)
        nb = M.Neighborhood.query.get(name='Users')
        projects = (M.Project.query.find({
            'neighborhood_id': {
                '$ne': nb._id
            },
            'deleted': False,
            '_id': {
                '$lt': start,
                '$gt': end
            },
        }).sort('_id', -1)).all()
        # pre-populate roles cache, so we won't query mongo for roles for every project
        # when getting admins with p.admins() in a template
        Credentials.get().load_project_roles(*[p._id for p in projects])
        step = start_dt - end_dt
        params = request.params.copy()
        params['start-dt'] = (start_dt + step).strftime('%Y/%m/%d %H:%M:%S')
        params['end-dt'] = (end_dt + step).strftime('%Y/%m/%d %H:%M:%S')
        newer_url = tg.url(params=params).lstrip('/')
        params['start-dt'] = (start_dt - step).strftime('%Y/%m/%d %H:%M:%S')
        params['end-dt'] = (end_dt - step).strftime('%Y/%m/%d %H:%M:%S')
        older_url = tg.url(params=params).lstrip('/')
        return {
            'projects': projects,
            'newer_url': newer_url,
            'older_url': older_url,
            'window_start': start_dt,
            'window_end': end_dt,
        }

    @expose('jinja:allura:templates/site_admin_reclone_repo.html')
    @without_trailing_slash
    @validate(
        dict(prefix=validators.NotEmpty(),
             shortname=validators.NotEmpty(),
             mount_point=validators.NotEmpty()))
    def reclone_repo(self,
                     prefix=None,
                     shortname=None,
                     mount_point=None,
                     **data):
        if request.method == 'POST':
            if c.form_errors:
                error_msg = 'Error: '
                for msg in list(c.form_errors):
                    names = {
                        'prefix': 'Neighborhood prefix',
                        'shortname': 'Project shortname',
                        'mount_point': 'Repository mount point'
                    }
                    error_msg += '%s: %s ' % (names[msg], c.form_errors[msg])
                    flash(error_msg, 'error')
                return dict(prefix=prefix,
                            shortname=shortname,
                            mount_point=mount_point)
            nbhd = M.Neighborhood.query.get(url_prefix='/%s/' % prefix)
            if not nbhd:
                flash('Neighborhood with prefix %s not found' % prefix,
                      'error')
                return dict(prefix=prefix,
                            shortname=shortname,
                            mount_point=mount_point)
            c.project = M.Project.query.get(shortname=shortname,
                                            neighborhood_id=nbhd._id)
            if not c.project:
                flash(
                    'Project with shortname %s not found in neighborhood %s' %
                    (shortname, nbhd.name), 'error')
                return dict(prefix=prefix,
                            shortname=shortname,
                            mount_point=mount_point)
            c.app = c.project.app_instance(mount_point)
            if not c.app:
                flash(
                    'Mount point %s not found on project %s' %
                    (mount_point, c.project.shortname), 'error')
                return dict(prefix=prefix,
                            shortname=shortname,
                            mount_point=mount_point)
            source_url = c.app.config.options.get('init_from_url')
            source_path = c.app.config.options.get('init_from_path')
            if not (source_url or source_path):
                flash('%s does not appear to be a cloned repo' % c.app,
                      'error')
                return dict(prefix=prefix,
                            shortname=shortname,
                            mount_point=mount_point)
            allura.tasks.repo_tasks.reclone_repo.post(prefix=prefix,
                                                      shortname=shortname,
                                                      mount_point=mount_point)
            flash('Repository is being recloned')
        else:
            prefix = 'p'
            shortname = ''
            mount_point = ''
        return dict(prefix=prefix,
                    shortname=shortname,
                    mount_point=mount_point)

    def _search(self,
                model,
                fields,
                add_fields,
                q=None,
                f=None,
                page=0,
                limit=None,
                **kw):
        all_fields = fields + [(fld, fld) for fld in add_fields]
        c.search_form = W.admin_search_form(all_fields)
        c.page_list = W.page_list
        c.page_size = W.page_size
        count = 0
        objects = []
        limit, page, start = g.handle_paging(limit, page, default=25)
        if q:
            if f in ('username', 'shortname'):
                # these are always lowercase, so search by lowercase
                q = q.lower()
            match = search.site_admin_search(model,
                                             q,
                                             f,
                                             rows=limit,
                                             start=start)
            if match:
                count = match.hits
                objects = match.docs

                ids = [obj['id'] for obj in objects]
                mongo_objects = search.mapped_artifacts_from_index_ids(
                    ids, model)
                for i in range(len(objects)):
                    obj = objects[i]
                    _id = obj['id'].split('#')[1]
                    obj['object'] = mongo_objects.get(_id)
                # Some objects can be deleted, but still have index in solr, should skip those
                objects = [o for o in objects if o.get('object')]

        def convert_fields(obj):
            # throw the type away (e.g. '_s' from 'url_s')
            result = {}
            for k, val in six.iteritems(obj):
                name = k.rsplit('_', 1)
                if len(name) == 2:
                    name = name[0]
                else:
                    name = k
                result[name] = val
            return result

        return {
            'q': q,
            'f': f,
            'objects': list(map(convert_fields, objects)),
            'count': count,
            'page': page,
            'limit': limit,
            'fields': fields,
            'additional_fields': add_fields,
            'type_s': model.type_s,
        }

    @without_trailing_slash
    @expose('jinja:allura:templates/site_admin_search.html')
    @validate(validators=dict(q=v.UnicodeString(if_empty=None),
                              limit=validators.Int(if_invalid=None),
                              page=validators.Int(if_empty=0, if_invalid=0)))
    def search_projects(self, q=None, f=None, page=0, limit=None, **kw):
        fields = [('shortname', 'shortname'), ('name', 'full name')]
        add_fields = aslist(
            tg.config.get('search.project.additional_search_fields'), ',')
        r = self._search(M.Project, fields, add_fields, q, f, page, limit,
                         **kw)
        r['search_results_template'] = 'allura:templates/site_admin_search_projects_results.html'
        r['additional_display_fields'] = \
            aslist(tg.config.get('search.project.additional_display_fields'), ',')
        r['provider'] = ProjectRegistrationProvider.get()
        return r

    @without_trailing_slash
    @expose('jinja:allura:templates/site_admin_search.html')
    @validate(validators=dict(q=v.UnicodeString(if_empty=None),
                              limit=validators.Int(if_invalid=None),
                              page=validators.Int(if_empty=0, if_invalid=0)))
    def search_users(self, q=None, f=None, page=0, limit=None, **kw):
        fields = [('username', 'username'), ('display_name', 'display name')]
        add_fields = aslist(
            tg.config.get('search.user.additional_search_fields'), ',')
        r = self._search(M.User, fields, add_fields, q, f, page, limit, **kw)
        r['objects'] = [
            dict(u, status=h.get_user_status(u['object']))
            for u in r['objects']
        ]
        r['search_results_template'] = 'allura:templates/site_admin_search_users_results.html'
        r['additional_display_fields'] = \
            aslist(tg.config.get('search.user.additional_display_fields'), ',')
        r['provider'] = AuthenticationProvider.get(request)
        return r
Exemplo n.º 22
0
 class fields(ew_core.NameList):
     name = ew.InputField(field_type='text',
                          label='Name',
                          validator=formencode.All(
                              V.UnicodeString(not_empty=True, max=40),
                              V.MaxBytesValidator(max=40),
                          ),
                          attrs={'maxlength': 40,
                                 'title': "This is the publicly viewable name of the project, and will appear on project listings. It should be what you want to see as the project title in search listing.",
                                 'class': 'tooltip',
                                 })
     summary = ew.InputField(field_type="text", label='Short Summary',
                             validator=formencode.All(
                                 V.UnicodeString(max=70),
                                 V.MaxBytesValidator(max=70)),
                             attrs={'maxlength': 70,
                                    'title': 'Briefly state what your project is and what it does without repeating the project name. This summary appears in Google search results beneath the project name.',
                                    'class': 'tooltip',
                                    })
     short_description = ew.TextArea(label='Full Description',
                                     validator=formencode.All(
                                         V.UnicodeString(max=1000),
                                         V.MaxBytesValidator(max=1000),
                                         ),
                                     attrs={
                                         'title': 'Describe the full functionality of your project using related keywords. The first sentence has the most impact on search. Provide unique content that calls out keywords and describes the merits of your project.',
                                         'class': 'tooltip'
                                     })
     # Apparently, child field must be CompoundField with custom template
     # for SortableRepeatedField to work properly, that's why FeaturesField
     # is not just ew.TextField
     features = ffw.SortableRepeatedField(
         label='Features',
         show_msg=False,
         show_button=False,
         append_to='bottom',
         extra_field_on_focus_name='feature',
         field=FeaturesField())
     icon = ew.FileField(label='Icon', attrs={'accept': 'image/*'},
                         validator=V.IconValidator())
     external_homepage = ew.InputField(field_type="text", label='Homepage',
                                       validator=fev.URL(add_http=True))
     video_url = ew.InputField(field_type="text", label="Video (YouTube)",
                               attrs={'title': 'Paste in a Youtube URL', 'class': 'tooltip'},
                               validator=V.YouTubeConverter())
     support_page = ew.InputField(field_type="text", label='Support Page')
     support_page_url = ew.InputField(
         field_type="text", label='Support Page URL',
         validator=fev.URL(add_http=True, if_empty=''))
     removal = ew.InputField(field_type="text", label='Removal')
     moved_to_url = ew.InputField(
         field_type="text", label='Moved Project to URL',
         validator=fev.URL(add_http=True, if_empty=''))
     delete = ew.InputField(field_type="hidden", label='Delete')
     delete_icon = ew.InputField(field_type="hidden", label='Delete Icon')
     undelete = ew.InputField(field_type="hidden", label='Undelete')
     tracking_id = ew.InputField(
         field_type="text", label="Google Analytics ID",
         attrs=(dict(placeholder='UA-123456-0', pattern='UA-[0-9]+-[0-9]+')))
     twitter_handle = ew.InputField(
         field_type="text", label='Twitter Handle')
     facebook_page = ew.InputField(field_type="text", label='Facebook page',
                                   validator=fev.URL(add_http=True))
Exemplo n.º 23
0
class GitHubWikiImportForm(ToolImportForm):
    gh_project_name = GitHubProjectNameValidator()
    gh_user_name = v.UnicodeString(not_empty=True)
    tool_option = v.UnicodeString(if_missing='')
Exemplo n.º 24
0
class ToolImportForm(schema.Schema):
    def __init__(self, tool_class):
        super(ToolImportForm, self).__init__()
        self.add_field('mount_point', v.MountPointValidator(tool_class))

    mount_label = v.UnicodeString()
Exemplo n.º 25
0
class RootController(BaseController):

    def __init__(self):
        c.short_url_lightbox = W.short_url_lightbox

    def _check_security(self):
        require_access(c.app, 'read')

    @expose('jinja:forgeshorturl:templates/index.html')
    @validate(dict(page=validators.Int(if_empty=0, if_invalid=0),
                   limit=validators.Int(if_empty=None, if_invalid=None)))
    def index(self, page=0, limit=None, **kw):
        c.page_list = W.page_list
        c.page_size = W.page_size
        limit, pagenum, start = g.handle_paging(limit, page, default=100)
        p = {'app_config_id': c.app.config._id}
        if not has_access(c.app, 'view_private'):
            p['private'] = False
        short_urls = (ShortUrl.query.find(p))
        count = short_urls.count()

        short_urls = short_urls.skip(start).limit(limit)

        return {
            'short_urls': short_urls,
            'limit': limit,
            'pagenum': pagenum,
            'count': count,
            'url_len': len(ShortUrl.build_short_url(c.app, short_name='')),
        }

    @expose('jinja:forgeshorturl:templates/search.html')
    @validate(dict(q=v.UnicodeString(if_empty=None),
                   project=validators.StringBool(if_empty=False)))
    def search(self, q=None, project=None, limit=None, page=0, **kw):
        c.search_results = W.search_results
        c.help_modal = W.search_help
        search_params = kw
        search_params.update({
            'q': q or '',
            'project': project,
            'limit': limit,
            'page': page,
            'allowed_types': ['ShortUrl'],
        })
        if not has_access(c.app, 'view_private'):
            search_params['fq'] = ['private_b:False']
        d = search_app(**search_params)
        d['search_comments_disable'] = True
        d['search_history_disable'] = True
        d['url_len'] = len(ShortUrl.build_short_url(c.app, short_name=''))
        return d

    @expose()
    def _lookup(self, pname, *remainder):
        query = {'app_config_id': c.app.config._id,
                 'short_name': pname}
        if not has_access(c.app, 'view_private'):
            query['private'] = False
        short_url = ShortUrl.query.find(query).first()
        if short_url:
            redirect(short_url.full_url)
        raise exc.HTTPNotFound()
Exemplo n.º 26
0
class WebhookCreateForm(schema.Schema):
    url = fev.URL(not_empty=True)
    secret = v.UnicodeString()
Exemplo n.º 27
0
 class fields(ew_core.NameList):
     newnumber = ew.TextField(label='New telephone number',
                              attrs={'value': ''},
                              validator=V.UnicodeString(not_empty=True))
Exemplo n.º 28
0
 class fields(ew_core.NameList):
     skypeaccount = ew.TextField(label='Skype account',
                                 attrs={'value': ''},
                                 validator=V.UnicodeString(not_empty=False))
Exemplo n.º 29
0
class RootController(BaseController, FeedController):
    def __init__(self):
        self._discuss = AppDiscussionController()

    def _check_security(self):
        require_access(c.app, 'read')

    @expose('jinja:forgeblog:templates/blog/index.html')
    @with_trailing_slash
    @validate(
        dict(page=validators.Int(if_empty=0, if_invalid=0),
             limit=validators.Int(if_empty=None, if_invalid=None)))
    def index(self, page=0, limit=None, **kw):
        query_filter = dict(app_config_id=c.app.config._id)
        if not has_access(c.app, 'write')():
            query_filter['state'] = 'published'
        q = BM.BlogPost.query.find(query_filter)
        post_count = q.count()
        limit, page, _ = g.handle_paging(limit, page)
        limit, page = h.paging_sanitizer(limit, page, post_count)
        posts = q.sort('timestamp', pymongo.DESCENDING) \
                 .skip(page * limit).limit(limit)
        c.form = W.preview_post_form
        c.pager = W.pager
        return dict(posts=posts, page=page, limit=limit, count=post_count)

    @with_trailing_slash
    @expose('jinja:forgeblog:templates/blog/search.html')
    @validate(
        dict(q=v.UnicodeString(if_empty=None),
             history=validators.StringBool(if_empty=False),
             search_comments=validators.StringBool(if_empty=False),
             project=validators.StringBool(if_empty=False)))
    def search(self,
               q=None,
               history=None,
               search_comments=None,
               project=None,
               limit=None,
               page=0,
               **kw):
        c.search_results = W.search_results
        c.help_modal = W.help_modal
        search_params = kw
        search_params.update({
            'q':
            q or '',
            'history':
            history,
            'search_comments':
            search_comments,
            'project':
            project,
            'limit':
            limit,
            'page':
            page,
            'allowed_types': ['Blog Post', 'Blog Post Snapshot'],
            'fq': ['state_s:published']
        })
        return search_app(**search_params)

    @expose('jinja:forgeblog:templates/blog/edit_post.html')
    @without_trailing_slash
    def new(self, **kw):
        require_access(c.app, 'write')
        self.rate_limit(BM.BlogPost, 'Create/edit', c.app.config.url())
        post = dict(state='published')
        c.form = W.new_post_form
        return dict(
            post=post,
            subscribed_to_tool=M.Mailbox.subscribed(),
        )

    @memorable_forget()
    @expose()
    @require_post()
    # both new & edit submit here, but validate with new since it adds a field (subscribe)
    @validate(form=W.new_post_form, error_handler=new)
    @without_trailing_slash
    def save(self, **kw):
        require_access(c.app, 'write')
        self.rate_limit(BM.BlogPost, 'Create/edit', c.app.config.url())
        attachment = kw.pop('attachment', None)
        post = BM.BlogPost.new(**kw)
        g.spam_checker.check(kw['title'] + '\n' + kw['text'],
                             artifact=post,
                             user=c.user,
                             content_type='blog-post')
        if attachment is not None:
            post.add_multiple_attachments(attachment)
        notification_tasks.send_usermentions_notification.post(
            post.index_id(), kw['text'])
        redirect(h.urlquote(h.really_unicode(post.url())))

    @with_trailing_slash
    @expose('jinja:allura:templates/markdown_syntax_dialog.html')
    def markdown_syntax_dialog(self, **kw):
        'Static dialog page about how to use markdown.'
        return dict()

    @expose()
    def _lookup(self, year=None, month=None, name=None, *rest):
        if year is None or month is None or name is None:
            raise exc.HTTPNotFound()
        slug = '/'.join((year, month,
                         six.moves.urllib.parse.unquote(name).decode('utf-8')))
        post = BM.BlogPost.query.get(slug=slug, app_config_id=c.app.config._id)
        if post is None:
            raise exc.HTTPNotFound()
        return PostController(post), rest

    def get_feed(self, project, app, user):
        """
        Return a :class:`allura.controllers.feed.FeedArgs` object describing the xml feed for this controller.
        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.
        """
        return FeedArgs(
            dict(project_id=project._id,
                 app_config_id=app.config._id,
                 link=BM.BlogPost.link_regex),
            'Recent posts to %s' % app.config.options.mount_point, app.url)
Exemplo n.º 30
0
class RootController(BaseController, DispatchIndex, FeedController):
    class W(object):
        new_topic = DW.NewTopicPost(submit_text='Post')

        announcements_table = FW.AnnouncementsTable()
        add_forum = AddForumShort()
        search_results = SearchResults()
        search_help = SearchHelp(
            comments=False,
            history=False,
            fields={
                'author_user_name_t': 'Username',
                'text': '"Post text"',
                'timestamp_dt':
                'Date posted.  Example: timestamp_dt:[2018-01-01T00:00:00Z TO *]',
                'name_s': 'Subject'
            })

    def _check_security(self):
        require_access(c.app, 'read')

    @with_trailing_slash
    @expose('jinja:forgediscussion:templates/discussionforums/index.html')
    def index(self, new_forum=False, **kw):
        c.add_forum = self.W.add_forum
        c.announcements_table = self.W.announcements_table
        announcements = model.ForumThread.query.find(
            dict(
                app_config_id=c.app.config._id,
                flags='Announcement',
            )).all()
        forums = model.Forum.query.find(
            dict(app_config_id=c.app.config._id, parent_id=None,
                 deleted=False)).all()
        forums = [f for f in forums if h.has_access(f, 'read')()]
        return dict(forums=forums,
                    announcements=announcements,
                    hide_forum=(not new_forum))

    @expose('jinja:forgediscussion:templates/discussionforums/index.html')
    def new_forum(self, **kw):
        require_access(c.app, 'configure')
        return self.index(new_forum=True, **kw)

    @h.vardec
    @expose()
    @require_post()
    @validate(form=W.add_forum, error_handler=index)
    def add_forum_short(self, add_forum=None, **kw):
        require_access(c.app, 'configure')
        f = utils.create_forum(c.app, add_forum)
        redirect(f.url())

    @with_trailing_slash
    @expose(
        'jinja:forgediscussion:templates/discussionforums/create_topic.html')
    def create_topic(self, forum_name=None, new_forum=False, **kw):
        forums = model.Forum.query.find(
            dict(app_config_id=c.app.config._id, parent_id=None,
                 deleted=False))
        c.new_topic = self.W.new_topic
        my_forums = []
        forum_name = h.really_unicode(
            unquote(forum_name)) if forum_name else None
        current_forum = None
        for f in forums:
            if forum_name == f.shortname:
                current_forum = f
            if has_access(f, 'post')():
                my_forums.append(f)
        return dict(
            forums=my_forums,
            current_forum=current_forum,
            subscribed=M.Mailbox.subscribed(artifact=current_forum),
            subscribed_to_tool=M.Mailbox.subscribed(),
        )

    @memorable_forget()
    @h.vardec
    @expose()
    @require_post()
    @validate(W.new_topic, error_handler=create_topic)
    @AntiSpam.validate('Spambot protection engaged', error_url='create_topic')
    def save_new_topic(self,
                       subject=None,
                       text=None,
                       forum=None,
                       subscribe=False,
                       **kw):
        self.rate_limit(model.ForumPost, 'Topic creation',
                        six.ensure_text(request.referer or '/'))
        discussion = model.Forum.query.get(app_config_id=c.app.config._id,
                                           shortname=forum)
        if discussion.deleted and not has_access(c.app, 'configure')():
            flash('This forum has been removed.')
            redirect(six.ensure_text(request.referer or '/'))
        require_access(discussion, 'post')
        thd = discussion.get_discussion_thread(
            dict(headers=dict(Subject=subject)))[0]
        p = thd.post(subject, text, subscribe=subscribe)
        if 'attachment' in kw:
            p.add_multiple_attachments(kw['attachment'])
        thd.post_to_feed(p)
        flash('Message posted')
        redirect(thd.url())

    @with_trailing_slash
    @expose('jinja:forgediscussion:templates/discussionforums/search.html')
    @validate(
        dict(q=v.UnicodeString(if_empty=None),
             history=validators.StringBool(if_empty=False),
             project=validators.StringBool(if_empty=False),
             limit=validators.Int(if_empty=None, if_invalid=None),
             page=validators.Int(if_empty=0, if_invalid=0)))
    def search(self,
               q=None,
               history=None,
               project=None,
               limit=None,
               page=0,
               **kw):
        c.search_results = self.W.search_results
        c.help_modal = self.W.search_help
        search_params = kw
        search_params.update({
            'q':
            q or '',
            'history':
            history,
            'project':
            project,
            'limit':
            limit,
            'page':
            page,
            'allowed_types': ['Post', 'Post Snapshot', 'Discussion', 'Thread'],
        })
        d = search_app(**search_params)
        d['search_comments_disable'] = True
        return d

    @expose('jinja:allura:templates/markdown_syntax.html')
    def markdown_syntax(self, **kw):
        'Static page explaining markdown.'
        return dict()

    @with_trailing_slash
    @expose('jinja:allura:templates/markdown_syntax_dialog.html')
    def markdown_syntax_dialog(self, **kw):
        'Static dialog page about how to use markdown.'
        return dict()

    @expose()
    def _lookup(self, id=None, *remainder):
        if id:
            id = unquote(id)
            forum = model.Forum.query.get(app_config_id=c.app.config._id,
                                          shortname=id)
            if forum is None:
                raise exc.HTTPNotFound()
            c.forum = forum
            return ForumController(id), remainder
        else:
            raise exc.HTTPNotFound()

    def get_feed(self, project, app, user):
        """Return a :class:`allura.controllers.feed.FeedArgs` object describing
        the xml feed for this controller.

        Overrides :meth:`allura.controllers.feed.FeedController.get_feed`.

        """
        return FeedArgs(
            dict(project_id=project._id, app_config_id=app.config._id),
            'Recent posts to %s' % app.config.options.mount_label, app.url)

    @without_trailing_slash
    @expose('jinja:forgediscussion:templates/discussionforums/stats_graph.html'
            )
    def stats(self, dates=None, forum=None, **kw):
        if not dates:
            dates = "{} to {}".format(
                (date.today() - timedelta(days=60)).strftime('%Y-%m-%d'),
                date.today().strftime('%Y-%m-%d'))
        return dict(
            dates=dates,
            selected_forum=forum,
        )

    @expose('json:')
    @validate(
        dict(
            begin=h.DateTimeConverter(if_empty=None, if_invalid=None),
            end=h.DateTimeConverter(if_empty=None, if_invalid=None),
        ))
    def stats_data(self, begin=None, end=None, forum=None, **kw):
        end = end or date.today()
        begin = begin or end - timedelta(days=60)

        discussion_id_q = {
            '$in':
            [d._id for d in c.app.forums if d.shortname == forum or not forum]
        }
        # must be ordered dict, so that sorting by this works properly
        grouping = OrderedDict()
        grouping['year'] = {'$year': '$timestamp'}
        grouping['month'] = {'$month': '$timestamp'}
        grouping['day'] = {'$dayOfMonth': '$timestamp'}
        mongo_data = model.ForumPost.query.aggregate(
            [
                {
                    '$match': {
                        'discussion_id': discussion_id_q,
                        'status': 'ok',
                        'timestamp': {
                            # convert date to datetime to make pymongo happy
                            '$gte': datetime.combine(begin, time.min),
                            '$lte': datetime.combine(end, time.max),
                        },
                        'deleted': False,
                    }
                },
                {
                    '$group': {
                        '_id': grouping,
                        'posts': {
                            '$sum': 1
                        },
                    }
                },
                {
                    '$sort': {
                        '_id': pymongo.ASCENDING,
                    }
                },
            ],
            cursor={})

        def reformat_data(mongo_data):
            def item(day, val):
                return [calendar.timegm(day.timetuple()) * 1000, val]

            next_expected_date = begin
            for d in mongo_data:
                this_date = datetime(d['_id']['year'], d['_id']['month'],
                                     d['_id']['day'])
                for day in h.daterange(next_expected_date, this_date):
                    yield item(day, 0)
                yield item(this_date, d['posts'])
                next_expected_date = this_date + timedelta(days=1)
            for day in h.daterange(next_expected_date,
                                   end + timedelta(days=1)):
                yield item(day, 0)

        return dict(
            begin=begin,
            end=end,
            data=list(reformat_data(mongo_data)),
        )