Exemplo n.º 1
0
class Blog(Default):
    itemtype = ITEMTYPE_BLOG
    display_name = L_('Blog')
    description = L_('Blog item')
    order = 0

    class _ModifyForm(Default._ModifyForm):
        meta_form = BlogMetaForm
        meta_template = 'blog/modify_main_meta.html'

    def do_show(self, revid):
        """
        Show a blog item and a list of its blog entries below it.

        If tag GET-parameter is defined, the list of blog entries consists only
        of those entries that contain the tag value in their lists of tags.
        """
        # for now it is just one tag=value, later it could be tag=value1&tag=value2&...
        tag = request.values.get('tag')
        prefix = self.name + '/'
        current_timestamp = int(time.time())
        terms = [
            Term(WIKINAME, app.cfg.interwikiname),
            # Only blog entry itemtypes
            Term(ITEMTYPE, ITEMTYPE_BLOG_ENTRY),
            # Only sub items of this item
            Prefix(NAME_EXACT, prefix),
        ]
        if tag:
            terms.append(Term(TAGS, tag))
        query = And(terms)

        def ptime_sort_key(searcher, docnum):
            """
            Compute the publication time key for blog entries sorting.

            If PTIME is not defined, we use MTIME.
            """
            fields = searcher.stored_fields(docnum)
            ptime = fields.get(PTIME, fields[MTIME])
            return ptime

        ptime_sort_facet = FunctionFacet(ptime_sort_key)

        revs = flaskg.storage.search(query,
                                     sortedby=ptime_sort_facet,
                                     reverse=True,
                                     limit=None)
        blog_entry_items = [
            Item.create(rev.name, rev_id=rev.revid) for rev in revs
        ]
        return render_template(
            'blog/main.html',
            item_name=self.name,
            fqname=split_fqname(self.name),
            blog_item=self,
            blog_entry_items=blog_entry_items,
            tag=tag,
            item=self,
        )
Exemplo n.º 2
0
 def _load(self, item):
     super(TicketUpdateForm, self)._load(item)
     self['submit'].properties['labels'] = {
         'update': L_('Update ticket'),
         'update_negate_status': (L_('Update & reopen ticket') if item.meta.get('closed')
                                  else L_('Update & close ticket'))
     }
Exemplo n.º 3
0
class BlogEntry(Default):
    itemtype = ITEMTYPE_BLOG_ENTRY
    display_name = L_('Blog entry')
    description = L_('Blog entry item')
    order = 0

    class _ModifyForm(Default._ModifyForm):
        meta_form = BlogEntryMetaForm
        meta_template = 'blog/modify_entry_meta.html'

        @classmethod
        def from_item(cls, item):
            form = super(BlogEntry._ModifyForm, cls).from_item(item)
            # preload PTIME with the current datetime
            if not form['meta_form']['ptime']:
                form['meta_form']['ptime'].set(datetime.utcnow())
            return form

    def do_show(self, revid):
        blog_item_name = self.name.rsplit('/', 1)[0]
        try:
            blog_item = Item.create(blog_item_name)
        except AccessDenied:
            abort(403)
        if not isinstance(blog_item, Blog):
            # The parent item of this blog entry item is not a Blog item.
            abort(403)
        return render_template(
            'blog/entry.html',
            item_name=self.name,
            fqname=blog_item.fqname,
            blog_item=blog_item,
            blog_entry_item=self,
            item=self,
        )
Exemplo n.º 4
0
class ValidJSON(Validator):
    """Validator for JSON
    """
    invalid_json_msg = L_('Invalid JSON.')
    invalid_itemid_msg = L_('Itemid not a proper UUID')
    invalid_namespace_msg = ''

    def validitemid(self, itemid):
        if not itemid:
            self.invalid_itemid_msg = L_("No ITEMID field")
            return False
        return uuid_validator(String(itemid), None)

    def validnamespace(self, current_namespace):
        if current_namespace is None:
            self.invalid_namespace_msg = L_("No namespace field in the meta.")
            return False
        namespaces = [namespace.rstrip('/') for namespace, _ in app.cfg.namespace_mapping]
        if current_namespace not in namespaces:  # current_namespace must be an existing namespace.
            self.invalid_namespace_msg = L_("%(_namespace)s is not a valid namespace.", _namespace=current_namespace)
            return False
        return True

    def validate(self, element, state):
        try:
            meta = json.loads(element.value)
        except:  # noqa - catch ANY exception that happens due to unserializing
            return self.note_error(element, state, 'invalid_json_msg')
        if not self.validnamespace(meta.get(NAMESPACE)):
            return self.note_error(element, state, 'invalid_namespace_msg')
        if state[FQNAME].field == ITEMID:
            if not self.validitemid(meta.get(ITEMID, state[FQNAME].value)):
                return self.note_error(element, state, 'invalid_itemid_msg')
        return True
Exemplo n.º 5
0
def modify_acl(item_name):
    fqname = split_fqname(item_name)
    item = Item.create(item_name)
    meta = dict(item.meta)
    old_acl = meta.get(ACL, '')
    new_acl = request.form.get(fqname.fullname)
    is_valid = acl_validate(new_acl)
    if is_valid:
        if new_acl in ('Empty', ''):
            meta[ACL] = ''
        elif new_acl == 'None' and ACL in meta:
            del (meta[ACL])
        else:
            meta[ACL] = new_acl
        try:
            item._save(meta=meta)
        except AccessDenied:
            # superuser viewed item acl report and tried to change acl but lacked admin permission
            flash(
                L_("Failed! Not authorized.<br>Item: %(item_name)s<br>ACL: %(acl_rule)s",
                   item_name=fqname.fullname,
                   acl_rule=old_acl), "error")
            return redirect(url_for('.item_acl_report'))
        flash(
            L_("Success! ACL saved.<br>Item: %(item_name)s<br>ACL: %(acl_rule)s",
               item_name=fqname.fullname,
               acl_rule=new_acl), "info")
    else:
        flash(
            L_("Nothing changed, invalid ACL.<br>Item: %(item_name)s<br>ACL: %(acl_rule)s",
               item_name=fqname.fullname,
               acl_rule=new_acl), "error")
    return redirect(url_for('.item_acl_report'))
Exemplo n.º 6
0
class Userprofile(Item):
    """
    Currently userprofile is implemented as a contenttype. This is a stub of an
    itemtype implementation of userprofile.
    """
    itemtype = ITEMTYPE_USERPROFILE
    display_name = L_('User profile')
    description = L_('User profile item (not implemented yet!)')
Exemplo n.º 7
0
 def validnamespace(self, current_namespace):
     if current_namespace is None:
         self.invalid_namespace_msg = L_("No namespace field in the meta.")
         return False
     namespaces = [namespace.rstrip('/') for namespace, _ in app.cfg.namespace_mapping]
     if current_namespace not in namespaces:  # current_namespace must be an existing namespace.
         self.invalid_namespace_msg = L_("%(_namespace)s is not a valid namespace.", _namespace=current_namespace)
         return False
     return True
Exemplo n.º 8
0
class RegisterNewUserForm(Form):
    """
    Simple user registration form for use by SuperUsers to create new accounts.
    """
    name = 'register_new_user'
    username = RequiredText.using(label=L_('Username')).with_properties(placeholder=L_("User Name"), autofocus=True)
    email = YourEmail
    submit_label = L_('Register')
    validators = [ValidRegisterNewUser()]
Exemplo n.º 9
0
def validate_name(meta, itemid):
    """
    Check whether the names are valid.
    Will just return, if they are valid, will raise a NameNotValidError if not.
    """
    names = meta.get(NAME)
    current_namespace = meta.get(NAMESPACE)
    if current_namespace is None:
        raise NameNotValidError(L_("No namespace field in the meta."))
    namespaces = [
        namespace.rstrip('/') for namespace, _ in app.cfg.namespace_mapping
    ]

    if len(names) != len(set(names)):
        msg = L_("The names in the name list must be unique.")
        flash(msg, "error")  # duplicate message at top of form
        raise NameNotValidError(msg)
    # Item names must not start with '@' or '+', '@something' denotes a field where as '+something' denotes a view.
    invalid_names = [name for name in names if name.startswith(('@', '+'))]
    if invalid_names:
        msg = L_(
            "Item names (%(invalid_names)s) must not start with '@' or '+'",
            invalid_names=", ".join(invalid_names))
        flash(msg, "error")  # duplicate message at top of form
        raise NameNotValidError(msg)

    namespaces = namespaces + NAMESPACES_IDENTIFIER  # Also dont allow item names to match with identifier namespaces.
    # Item names must not match with existing namespaces.
    invalid_names = [
        name for name in names if name.split('/', 1)[0] in namespaces
    ]
    if invalid_names:
        msg = L_(
            "Item names (%(invalid_names)s) must not match with existing namespaces.",
            invalid_names=", ".join(invalid_names))
        flash(msg, "error")  # duplicate message at top of form
        raise NameNotValidError(msg)
    query = And([
        Or([Term(NAME, name) for name in names]),
        Term(NAMESPACE, current_namespace)
    ])
    # There should be not item existing with the same name.
    if itemid is not None:
        query = And([query, Not(Term(ITEMID, itemid))
                     ])  # search for items except the current item.
    with flaskg.storage.indexer.ix[LATEST_REVS].searcher() as searcher:
        results = searcher.search(query)
        duplicate_names = {
            name
            for result in results for name in result[NAME] if name in names
        }
        if duplicate_names:
            msg = L_("Item(s) named %(duplicate_names)s already exist.",
                     duplicate_names=", ".join(duplicate_names))
            flash(msg, "error")  # duplicate message at top of form
            raise NameNotValidError(msg)
Exemplo n.º 10
0
class TicketBackRefForm(Form):
    supersedes = BackReference.using(label=L_("Supersedes"))
    required_by = BackReference.using(label=L_("Required By"))
    subscribers = BackReference.using(label=L_("Subscribers"))

    def _load(self, item):
        id_ = item.meta[ITEMID]
        self['supersedes'].set(Term(SUPERSEDED_BY, id_))
        self['required_by'].set(Term(DEPENDS_ON, id_))
        self['subscribers'].set(Term(SUBSCRIPTIONS, id_))
Exemplo n.º 11
0
class TicketForm(BaseModifyForm):
    meta = TicketMetaForm
    backrefs = TicketBackRefForm
    message = OptionalMultilineText.using(label=L_("Message")).with_properties(rows=8, cols=80)
    data_file = File.using(optional=True, label=L_('Upload file:'))

    def _load(self, item):
        meta = item.prepare_meta_for_modify(item.meta)
        self['meta'].set(meta, 'duck')
        # XXX need a more explicit way to test for item creation/modification
        if ITEMID in item.meta:
            self['backrefs']._load(item)
Exemplo n.º 12
0
class TicketMetaForm(Form):
    summary = Text.using(label=L_("Summary"), optional=False).with_properties(
        widget=WIDGET_SEARCH, placeholder=L_("One-line summary"))
    effort = Rating.using(label=L_("Effort"))
    difficulty = Rating.using(label=L_("Difficulty"))
    severity = Rating.using(label=L_("Severity"))
    priority = Rating.using(label=L_("Priority"))
    tags = Tags.using(optional=True)
    assigned_to = OptionalUserReference.using(label=L_("Assigned To"))
    superseded_by = OptionalTicketReference.using(label=L_("Superseded By"))
    depends_on = OptionalTicketReference.using(label=L_("Depends On"))
Exemplo n.º 13
0
 def delete(self, comment=u''):
     """
     delete this item (remove current name from NAME list)
     """
     item_modified.send(app, fqname=self.fqname, action=ACTION_TRASH, meta=self.meta,
                        content=self.rev.data, comment=comment)
     ret = self._rename(None, comment, action=ACTION_TRASH, delete=True)
     if [self.name] == self.names:
         flash(L_('The item "%(name)s" was deleted.', name=self.name), 'info')
     else:
         # the item has several names, we deleted only one name
         name_list = [x for x in self.names if not x == self.name]
         msg = L_('The item name "%(name)s" was deleted, the item persists with alias names: "%(name_list)s"', name=self.name, name_list=name_list)
         flash(msg, 'info')
     return ret
Exemplo n.º 14
0
def themed_error(e):
    item_name = request.view_args.get('item_name', u'')
    if e.code == 403:
        title = L_('Access Denied')
        description = L_('You are not allowed to access this resource.')
        if e.description.startswith(' '):
            # leading blank indicates supplemental info, not standard werkzeug message
            description += e.description
    else:
        # if we have no special code, we just return the HTTPException instance
        return e
    content = render_template('error.html',
                              item_name=item_name,
                              title=title, description=description)
    return content, e.code
Exemplo n.º 15
0
    def unlock_item(self, cancel=False):
        """
        Return None if OK, else return 'locked by someone else' message.

        Called on Cancel and OK/save processing.
        """
        user_name = self.user_name
        locked = self.get_lock_status()
        if locked:
            i_id, i_name, u_name, timeout = locked
            if u_name == user_name:
                self.cursor.execute(
                    '''DELETE FROM editlock WHERE item_id = ? ''',
                    (self.item_id, ))
                self.conn.commit()
                return
            elif not cancel:
                # bug: someone else has active edit lock, relock_item() should have been called prior to item save
                logging.error(
                    "User {0} tried to unlock item that was locked by someone else: {1}"
                    .format(user_name, i_name))
                msg = L_(
                    "Item '%(item_name)s' is locked by %(user_name)s. Edit lock error, check Item History to verify no changes were lost.",
                    item_name=i_name,
                    user_name=u_name,
                )
                return msg
        if not cancel:
            # bug: there should have been a lock_item call prior to unlock call
            logging.error(
                "User {0} tried to unlock item that was not locked: {1}".
                format(user_name, self.item_name))
Exemplo n.º 16
0
def register_new_user():
    """
    Create a new account and send email with link to create password.
    """
    if not _using_moin_auth():
        return Response('No MoinAuth in auth list', 403)

    title_name = _('Register New User')
    FormClass = RegisterNewUserForm

    if request.method in ['GET', 'HEAD']:
        form = FormClass.from_defaults()
    elif request.method == 'POST':
        form = FormClass.from_flat(request.form)
        if form.validate():
            username = form['username'].value
            email = form['email'].value
            user_profile = user.UserProfile()
            user_profile[ITEMID] = make_uuid()
            user_profile[NAME] = [
                username,
            ]
            user_profile[EMAIL] = email
            user_profile[DISABLED] = False
            user_profile[ACTION] = ACTION_SAVE

            users = user.search_users(**{NAME_EXACT: username})
            if users:
                flash(_('User already exists'), 'error')
            emails = None
            if app.cfg.user_email_unique:
                emails = user.search_users(email=email)
                if emails:
                    flash(_("This email already belongs to somebody else."),
                          'error')
            if not (users or emails):
                user_profile.save()
                flash(_("Account for %(username)s created", username=username),
                      "info")
                form = FormClass.from_defaults()

                u = user.User(auth_username=username)
                if u.valid:
                    is_ok, msg = u.mail_password_recovery()
                    if not is_ok:
                        flash(msg, "error")
                    else:
                        flash(
                            L_("%(username)s has been sent a password recovery email.",
                               username=username), "info")
                else:
                    flash(
                        _("%(username)s is an invalid user, no email has been sent.",
                          username=username), "error")

    return render_template(
        'admin/register_new_user.html',
        title_name=title_name,
        form=form,
    )
Exemplo n.º 17
0
class Reference(
        Select.with_properties(empty_label=L_('(None)')).validated_by(
            ValidReference())):
    """
    A metadata property that points to another item selected out of the
    Results of a search query.
    """
    @class_cloner
    def to(cls, query, query_args={}):
        cls._query = query
        cls._query_args = query_args
        return cls

    @classmethod
    def _get_choice_specs(cls):
        revs = flaskg.storage.search(cls._query, **cls._query_args)
        label_getter = cls.properties['label_getter']
        choices = [(rev.meta[ITEMID], label_getter(rev)) for rev in revs]
        if cls.optional:
            choices.append(('', cls.properties['empty_label']))
        return choices

    def __init__(self, value=Unspecified, **kw):
        super(Reference, self).__init__(value, **kw)
        # NOTE There is a slight chance of two instances of the same Reference
        # subclass having different set of choices when the storage changes
        # between their initialization.
        choice_specs = self._get_choice_specs()
        self.properties['choice_specs'] = choice_specs
        self.valid_values = [id_ for id_, name in choice_specs]
Exemplo n.º 18
0
def modify_acl(item_name):
    fqname = split_fqname(item_name)
    item = Item.create(item_name)
    meta = dict(item.meta)
    new_acl = request.form.get(fqname.fullname)
    is_valid = acl_validate(new_acl)
    if is_valid:
        if new_acl in ('Empty', ''):
            meta[ACL] = ''
        elif new_acl == 'None' and ACL in meta:
            del(meta[ACL])
        else:
            meta[ACL] = new_acl
        item._save(meta=meta)
        flash(L_("Success! ACL saved.<br>Item: %(item_name)s<br>ACL: %(acl_rule)s", item_name=fqname.fullname, acl_rule=new_acl), "info")
    else:
        flash(L_("Nothing changed, invalid ACL.<br>Item: %(item_name)s<br>ACL: %(acl_rule)s", item_name=fqname.fullname, acl_rule=new_acl), "error")
    return redirect(url_for('.item_acl_report'))
Exemplo n.º 19
0
class AdvancedSearchForm(Form):
    q = Search
    summary = Text.using(label=L_("Summary"), optional=False).with_properties(
        widget=WIDGET_SEARCH, placeholder=L_("Find Tickets"))
    effort = Rating.using(label=L_("Effort"))
    difficulty = Rating.using(label=L_("Difficulty"))
    severity = Rating.using(label=L_("Severity"))
    priority = Rating.using(label=L_("Priority"))
    tags = Tags.using(optional=True)
    assigned_to = OptionalUserReference.using(label=L_("Assigned To"))
    author = OptionalUserReference.using(label=L_("Author"))
Exemplo n.º 20
0
def message_markup(message):
    """
    Add a heading with author and timestamp to message (aka ticket description).
    """
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    heading = L_('{author} wrote on {timestamp}:').format(author=flaskg.user.name[0], timestamp=timestamp)
    message = u'{heading}\n\n{message}'.format(heading=heading, message=message)
    return u"""{{{{{{#!wiki moin-ticket
%(message)s
}}}}}}""" % dict(message=message)
Exemplo n.º 21
0
 def destroy(self, comment=u'', destroy_item=False, subitem_names=[]):
     # called from destroy UI/POST
     action = DESTROY_ALL if destroy_item else DESTROY_REV
     item_modified.send(app, fqname=self.fqname, action=action, meta=self.meta,
                        content=self.rev.data, comment=comment)
     close_file(self.rev.data)
     if destroy_item:
         # destroy complete item with all revisions, metadata, etc.
         self.rev.item.destroy_all_revisions()
         # destroy all subitems
         for subitem_name in subitem_names:
             item = Item.create(subitem_name, rev_id=CURRENT)
             close_file(item.rev.data)
             item.rev.item.destroy_all_revisions()
         flash(L_('The item "%(name)s" was destroyed.', name=self.name), 'info')
     else:
         # just destroy this revision
         self.rev.item.destroy_revision(self.rev.revid)
         flash(L_('Rev Number %(rev_number)s of the item "%(name)s" was destroyed.', rev_number=self.meta['rev_number'], name=self.name), 'info')
Exemplo n.º 22
0
class ValidReference(Validator):
    """
    Validator for Reference
    """
    invalid_reference_msg = L_('Invalid Reference.')

    def validate(self, element, state):
        if element.value not in element.valid_values:
            return self.note_error(element, state, 'invalid_reference_msg')
        return True
Exemplo n.º 23
0
 def rename(self, name, comment=u''):
     """
     rename this item to item <name> (replace current name by another name in the NAME list)
     """
     fqname = CompositeName(self.fqname.namespace, self.fqname.field, name)
     if flaskg.storage.get_item(**fqname.query):
         raise NameNotUniqueError(L_("An item named %s already exists in the namespace %s." % (name, fqname.namespace)))
     # if this is a subitem, verify all parent items exist
     _verify_parents(self, name, self.fqname.namespace, old_name=self.fqname.value)
     return self._rename(name, comment, action=ACTION_RENAME)
Exemplo n.º 24
0
    class _ModifyForm(BaseModifyForm):
        """
        ModifyForm (the form used on +modify view), sans the content part.
        Combined dynamically with the ModifyForm of the Content subclass in
        Contentful.ModifyForm.

        Subclasses of Contentful should generally override this instead of
        ModifyForm.
        """
        meta_form = BaseMetaForm
        extra_meta_text = JSON.using(
            label=L_("Extra MetaData (JSON)")).with_properties(rows=ROWS_META,
                                                               cols=COLS)
        meta_template = 'modify_meta.html'

        def _load(self, item):
            """
            Load metadata and data from :item into :self. Used by
            BaseModifyForm.from_item.
            """
            meta = item.prepare_meta_for_modify(item.meta)
            # Default value of `policy` argument of Flatland.Dict.set's is
            # 'strict', which causes KeyError to be thrown when meta contains
            # meta keys that are not present in self['meta_form']. Setting
            # policy to 'duck' suppresses this behavior.
            if 'acl' not in meta:
                meta['acl'] = "None"

            self['meta_form'].set(meta, policy='duck')
            for k in self['meta_form'].field_schema_mapping.keys(
            ) + IMMUTABLE_KEYS:
                meta.pop(k, None)
            self['extra_meta_text'].set(item.meta_dict_to_text(meta))
            self['content_form']._load(item.content)

        def _dump(self, item):
            """
            Dump useful data out of :self. :item contains the old item and
            should not be the primary data source; but it can be useful in case
            the data in :self is not sufficient.

            :returns: a tuple (meta, data, contenttype_guessed, comment),
                      suitable as arguments of the same names to pass to
                      item.modify
            """
            # Since the metadata form for tickets is an incomplete one, we load the
            # original meta and update it with those from the metadata editor
            # e.g. we get PARENTID in here
            meta = item.meta_filter(item.prepare_meta_for_modify(item.meta))
            meta.update(self['meta_form'].value)
            meta.update(item.meta_text_to_dict(self['extra_meta_text'].value))
            data, contenttype_guessed = self['content_form']._dump(
                item.content)
            comment = self['comment'].value
            return meta, data, contenttype_guessed, comment
Exemplo n.º 25
0
class BaseMetaForm(Form):

    itemtype = RequiredText.using(label=L_("Item type")).with_properties(placeholder=L_("Item type"))
    contenttype = RequiredText.using(label=L_("Content type")).with_properties(placeholder=L_("Content type"))
    # Flatland doesn't distinguish between empty value and nonexistent value, use None for noneexistent and Empty for empty
    acl = RequiredText.using(label=L_("ACL")).with_properties(placeholder=L_("Access Control List - Use 'None' for default")).validated_by(ACLValidator())
    summary = OptionalText.using(label=L_("Summary")).with_properties(placeholder=L_("One-line summary of the item"))
    name = Names
    tags = Tags
Exemplo n.º 26
0
class TextChaValid(Validator):
    """Validator for TextChas
    """
    textcha_incorrect_msg = L_('The entered TextCha was incorrect.')
    textcha_invalid_msg = L_(
        'The TextCha question is invalid or has expired. Please try again.')

    def validate(self, element, state):
        textcha = TextCha(element.parent)

        if textcha.is_enabled():
            if textcha.answer_re is None:
                textcha.init_qa()
                textcha.amend_form()
                element.set("")
                return self.note_error(element, state, 'textcha_invalid_msg')
            if textcha.answer_re.match(element.value.strip()) is None:
                return self.note_error(element, state, 'textcha_incorrect_msg')

        return True
Exemplo n.º 27
0
class ACLValidator(Validator):
    """
    Meta Validator - currently used for validating ACLs only
    """
    acl_fail_msg = L_("The ACL string is invalid.")

    def validate(self, element, state):
        if acl_validate(element) is True:
            return True
        flash(L_("The ACL string is invalid."), "error")
        return self.note_error(element, state, 'acl_fail_msg')
Exemplo n.º 28
0
class ValidSearch(Validator):
    """Validator for a valid search form
    """
    too_short_query_msg = L_('Search query too short.')

    def validate(self, element, state):
        if element['q'].value is None:
            # no query, nothing to search for
            return False
        if len(element['q'].value) < 2:
            return self.note_error(element, state, 'too_short_query_msg')
        return True
Exemplo n.º 29
0
def send_notifications(app, fqname, **kwargs):
    """ Send mail notifications to subscribers on item change

    :param app: local proxy app
    :param fqname: fqname of the changed item
    :param kwargs: key/value pairs that contain extra information about the item
                   required in order to create a notification
    """
    action = kwargs.get('action')
    revs = get_item_last_revisions(app, fqname) if action not in [
        DESTROY_REV,
        DESTROY_ALL,
    ] else []
    notification = Notification(app, fqname, revs, **kwargs)
    try:
        content_diff = notification.get_content_diff()
    except Exception:
        # current user has likely corrupted an item or fixed a corrupted item
        # or changed ACL and removed read access for himself
        # if current item is corrupt, another exception will occur in a downstream script
        content_diff = [
            u'- ' +
            _('An error has occurred, the current or prior revision of this item may be corrupt.'
              )
        ]
    meta_diff = notification.get_meta_diff()

    u = flaskg.user
    meta = kwargs.get('meta') if action in [
        DESTROY_REV,
        DESTROY_ALL,
    ] else revs[0].meta._meta
    subscribers = {
        subscriber
        for subscriber in get_subscribers(**meta)
        if subscriber.itemid != u.itemid
    }
    subscribers_locale = {subscriber.locale for subscriber in subscribers}
    for locale in subscribers_locale:
        with force_locale(locale):
            txt_msg, html_msg = notification.render_templates(
                content_diff, meta_diff)
            subject = L_(
                '[%(moin_name)s] Update of "%(fqname)s" by %(user_name)s',
                moin_name=app.cfg.interwikiname,
                fqname=unicode(fqname),
                user_name=u.name0)
            subscribers_emails = [
                subscriber.email for subscriber in subscribers
                if subscriber.locale == locale
            ]
            sendmail(subject, txt_msg, to=subscribers_emails, html=html_msg)
Exemplo n.º 30
0
class TicketSubmitForm(TicketForm):
    submit_label = L_("Submit ticket")

    def _dump(self, item):
        # initial metadata for Ticket-itemtyped item
        meta = {
            ITEMTYPE: item.itemtype,
            # XXX support other markups
            CONTENTTYPE: 'text/x.moin.wiki;charset=utf-8',
            'closed': False,
        }
        meta.update(self['meta'].value)
        return meta, message_markup(self['message'].value), None, self['data_file'].value