示例#1
0
    def test_basics(self):
        app = flask.Flask(__name__)
        b = babel.Babel(app, default_locale='de_DE')

        with app.test_request_context():
            assert gettext(u'Hello %(name)s!', name='Peter') == 'Hallo Peter!'
            assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 3) == u'3 Äpfel'
            assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 1) == u'1 Apfel'
示例#2
0
def score(runner_id):
    runner = db.runners.find_one({'number': runner_id})
    if runner is None:
        return jsonify({'success': False, 'message': _('Runner ID not found')})
    total_finished_runners = db.runners.find({'distance': runner['distance'],
                                              'result': {"$ne": None}}).count()
    finished_runners_in_group = db.runners.find({'group': runner['group'],
                                                 'gender': runner['gender'],
                                                 'distance': runner['distance'],
                                                 'result': {"$ne": None}}).count()

    position_in_group = db.runners.find({'group': runner['group'],
                                         'distance': runner['distance'],
                                         'gender': runner['gender'],
                                         'result': {"$lt": runner['result']}}).count()
    total_position = db.runners.find({'result': {"$lt": runner['result']},
                                      'distance': runner['distance']}).count()

    number_of_slower_runners_in_group = db.runners.find({'group': runner['group'],
                                                         'gender': runner['gender'],
                                                         'distance': runner['distance'],
                                                         'result': {"$gt": runner['result']}}).count()
    total_number_of_slower_runners = db.runners.find({'distance': runner['distance'],
                                                      'result': {"$gt": runner['result']}}).count()

    above_than_group = round((float(number_of_slower_runners_in_group) / float(finished_runners_in_group)) * 100.0)
    above_than_total = round((float(total_number_of_slower_runners) / float(total_finished_runners)) * 100.0)

    group_name = '{0} {1}'.format(genders_reversed[runner['gender']], runner['group'])

    msg = "Your time is %(time_result)s. This is %(position_in_group)s result " \
          "among %(total_finished_in_group)s people finished in your group %(group_name)s. " \
          "You run  %(distance)s km faster than %(above_than_group)s%% other participants in you group " \
          "and faster than %(above_than_total)s%% among all runners both genders " \
          "(%(total_position)s from %(total_runners)s)"
    num = 1 if runner['gender'] == 'm' else 2

    message = ngettext(msg, msg, num,
                       time_result=get_pretty_time(runner['result']),
                       position_in_group=position_in_group,
                       total_finished_in_group=finished_runners_in_group,
                       group_name=group_name,
                       distance=runner['distance'],
                       above_than_group=above_than_group,
                       above_than_total=above_than_total,
                       total_position=total_position,
                       total_runners=total_finished_runners)
    title_text = 'My ID %(runner_id) and I run %(distance)s km faster than %(above_than_group)s%% participants' \
                 ' #ergowhitenights 2016'
    title = ngettext(title_text, title_text, num,
                     runner_id=runner_id,
                     distance=runner['distance'],
                     above_than_group=above_than_group)
    return jsonify({'success': True,
                    'message': message,
                    'title': title})
示例#3
0
def timesince(dt, default=None):
    """
    Returns string representing "time since" e.g.
    3 days ago, 5 hours ago etc.
    """
    
    if default is None:
        default = gettext("just now")

    now = datetime.utcnow()
    diff = now - dt

    years = diff.days / 365
    months = diff.days / 30
    weeks = diff.days / 7
    days = diff.days
    hours = diff.seconds / 3600
    minutes = diff.seconds / 60
    seconds = diff.seconds 

    periods = (
        (years, ngettext("%(num)s year", "%(num)s years", num=years)),
        (months, ngettext("%(num)s month", "%(num)s months", num=months)),
        (weeks, ngettext("%(num)s week", "%(num)s weeks", num=weeks)),
        (days, ngettext("%(num)s day", "%(num)s days", num=days)),
        (hours, ngettext("%(num)s hour", "%(num)s hours", num=hours)),
        (minutes, ngettext("%(num)s minute", "%(num)s minutes", num=minutes)),
        (seconds, ngettext("%(num)s second", "%(num)s seconds", num=seconds)),
    )

    for period, trans in periods:
        if period:
            return gettext("%(period)s ago", period=trans)

    return default
示例#4
0
def bulk_delete(filesystem_id, items_selected):
    for item in items_selected:
        delete_file_object(item)

    flash(
        ngettext("Submission deleted.",
                 "{num} submissions deleted.".format(num=len(items_selected)),
                 len(items_selected)), "notification")
    return redirect(url_for('col.col', filesystem_id=filesystem_id))
示例#5
0
 def prepare_decks(self) -> None:
     self.is_very_large = self.is_very_large or len(getattr(self, 'decks', [])) > 500
     # The 'list' here is just to get past codacy and is a no-op.
     active_runs = [d for d in list(getattr(self, 'decks', [])) if d.is_in_current_run()]
     if len(active_runs) > 0:
         self.active_runs_text = ngettext('%(num)d active league run', '%(num)d active league runs', len(active_runs))
         self.decks = [d for d in self.decks if not d.is_in_current_run()]
     for d in getattr(self, 'decks', []):
         self.prepare_deck(d)
示例#6
0
def otp_secret_validation(form: FlaskForm, field: Field) -> None:
    strip_whitespace = field.data.replace(' ', '')
    input_length = len(strip_whitespace)
    if input_length != 40:
        raise ValidationError(
            ngettext(
                'HOTP secrets are 40 characters long - you have entered {num}.',
                'HOTP secrets are 40 characters long - you have entered {num}.',
                input_length).format(num=input_length))
示例#7
0
def main():
    # 输出语言测试结果
    common_text = gettext(u'CurrentLanguage')
    format_text = ngettext(u'%(num)d formattedLanguageExample',
                           u'%(num)d anotherFormattedLanguageExample', 100)
    print("Current Language:=", common_text)
    print("Formatted language string example:=", format_text)

    return render_template('index.html')
示例#8
0
def validate_user(
    username: str,
    password: Optional[str],
    token: Optional[str],
    error_message: Optional[str] = None,
) -> Optional[Journalist]:
    """
    Validates the user by calling the login and handling exceptions
    :param username: Username
    :param password: Password
    :param token: Two-factor authentication token
    :param error_message: Localized error message string to use on failure
    :return: Journalist user object if successful, None otherwise.
    """
    try:
        return Journalist.login(username, password, token)
    except (
            InvalidUsernameException,
            InvalidOTPSecretException,
            BadTokenException,
            WrongPasswordException,
            LoginThrottledException,
            InvalidPasswordLength,
    ) as e:
        current_app.logger.error("Login for '{}' failed: {}".format(
            username, e))
        login_flashed_msg = error_message if error_message else gettext(
            "Login failed.")

        if isinstance(e, LoginThrottledException):
            login_flashed_msg += " "
            period = Journalist._LOGIN_ATTEMPT_PERIOD
            # ngettext is needed although we always have period > 1
            # see https://github.com/freedomofpress/securedrop/issues/2422
            login_flashed_msg += ngettext(
                "Please wait at least {num} second before logging in again.",
                "Please wait at least {num} seconds before logging in again.",
                period,
            ).format(num=period)
        elif isinstance(e, InvalidOTPSecretException):
            login_flashed_msg += " "
            login_flashed_msg += gettext(
                "Your 2FA details are invalid"
                " - please contact an administrator to reset them.")
        else:
            try:
                user = Journalist.query.filter_by(username=username).one()
                if user.is_totp:
                    login_flashed_msg += " "
                    login_flashed_msg += gettext(
                        "Please wait for a new code from your two-factor mobile"
                        " app or security key before trying again.")
            except Exception:
                pass

        flash(login_flashed_msg, "error")
        return None
示例#9
0
def diff2html(s, diff, show_newlines=False):
    result = []
    ctx = max(0, current_app.config['DIFF_CONTEXT_SIZE'])
    offset = 0
    for i, item in enumerate(diff):
        act, data = item

        if act == '=':
            data = s[offset:offset + data]
            if len(data) < ctx * 3:
                result.append(escape(data))
            else:
                if ctx == 0:
                    l, mid, r = '', data, ''
                elif i == 0:
                    l, mid, r = '', data[:-ctx], data[-ctx:]
                elif i == len(diff) - 1:
                    l, mid, r = data[:ctx], data[ctx:], ''
                else:
                    l, mid, r = data[:ctx], data[ctx:-ctx], data[-ctx:]

                f = l.rfind(' ', 0, len(l) - 2)
                if f >= 0 and f > ctx - 30:
                    mid = l[f:] + mid
                    l = l[:f]
                f = r.find(' ', len(r) + 2)
                if f < ctx + 30:
                    mid = mid + r[:f + 1]
                    r = r[f + 1:]

                result.append(escape(l))
                result.append('<div class="editlog-expand-btn-wrap"><a href="#" class="editlog-expand-btn">')
                result.append(ngettext('Show %(num)s unchanged symbol', 'Show %(num)s unchanged symbols', len(mid)))
                result.append('</a></div><span class="editlog-unchanged" style="display: none;">')
                result.append(escape(mid))
                result.append('</span>')
                result.append(escape(r))
            offset += len(data)

        else:
            fancy_data = data
            if show_newlines:
                fancy_data = fancy_data.replace('\n', '⏎\n')

            if act == '+':
                result.append('<ins>')
                result.append(escape(fancy_data))
                result.append('</ins>')

            elif act == '-':
                result.append('<del>')
                result.append(escape(fancy_data))
                result.append('</del>')
                offset += len(data)

    return ''.join(result)
示例#10
0
def otp_secret_validation(form: FlaskForm, field: Field) -> None:
    strip_whitespace = field.data.replace(" ", "")
    input_length = len(strip_whitespace)
    if input_length != HOTP_SECRET_LENGTH:
        raise ValidationError(
            ngettext(
                "HOTP secrets are 40 characters long - you have entered {num}.",
                "HOTP secrets are 40 characters long - you have entered {num}.",
                input_length,
            ).format(num=input_length))
示例#11
0
 def bulk_delete(
     self, **kwargs: Any
 ) -> Response:  # pylint: disable=arguments-differ
     """Delete bulk Dashboards
     ---
     delete:
       description: >-
         Deletes multiple Dashboards in a bulk operation
       parameters:
       - in: query
         name: q
         content:
           application/json:
             schema:
               type: array
               items:
                 type: integer
       responses:
         200:
           description: Dashboard bulk delete
           content:
             application/json:
               schema:
                 type: object
                 properties:
                   message:
                     type: string
         401:
           $ref: '#/components/responses/401'
         403:
           $ref: '#/components/responses/403'
         404:
           $ref: '#/components/responses/404'
         422:
           $ref: '#/components/responses/422'
         500:
           $ref: '#/components/responses/500'
     """
     item_ids = kwargs["rison"]
     try:
         BulkDeleteDashboardCommand(g.user, item_ids).run()
         return self.response(
             200,
             message=ngettext(
                 f"Deleted %(num)d dashboard",
                 f"Deleted %(num)d dashboards",
                 num=len(item_ids),
             ),
         )
     except DashboardNotFoundError:
         return self.response_404()
     except DashboardForbiddenError:
         return self.response_403()
     except DashboardBulkDeleteFailedError as ex:
         return self.response_422(message=str(ex))
示例#12
0
def prettify_time_ago(t):
    """
    Converts seconds to a meaningful string.

    INPUT

    - t -- time in seconds

    """
    if t < 60:
        s = int(t)
        return ngettext('%(num)d second', '%(num)d seconds', s)
    if t < 3600:
        m = int(t / 60)
        return ngettext('%(num)d minute', '%(num)d minutes', m)
    if t < 3600 * 24:
        h = int(t / 3600)
        return ngettext('%(num)d hour', '%(num)d hours', h)
    d = int(t / (3600 * 24))
    return ngettext('%(num)d day', '%(num)d days', d)
示例#13
0
def bulk_delete(filesystem_id, items_selected):
    for item in items_selected:
        item_path = store.path(filesystem_id, item.filename)
        worker.enqueue(srm, item_path)
        db_session.delete(item)
    db_session.commit()

    flash(
        ngettext("Submission deleted.", "Submissions deleted.",
                 len(items_selected)), "notification")
    return redirect(url_for('col.col', filesystem_id=filesystem_id))
示例#14
0
    def calculate_date_difference(first_date, second_date):

        time = relativedelta(
            PlaceholderTransforms.parse_date(second_date),
            PlaceholderTransforms.parse_date(first_date),
        )

        if time.years:
            year_string = ngettext("{number_of_years} year",
                                   "{number_of_years} years", time.years)
            return year_string.format(number_of_years=time.years)

        if time.months:
            month_string = ngettext("{number_of_months} month",
                                    "{number_of_months} months", time.months)
            return month_string.format(number_of_months=time.months)

        day_string = ngettext("{number_of_days} day", "{number_of_days} days",
                              time.days)
        return day_string.format(number_of_days=time.days)
示例#15
0
 def prepare_active_runs(self, o: Any) -> None:
     decks = getattr(o, 'decks', [])
     active, other = [], []
     for d in decks:
         if d.is_in_current_run():
             active.append(d)
         else:
             other.append(d)
     if active and o.hide_active_runs:
         o.active_runs_text = ngettext('%(num)d active league run', '%(num)d active league runs', len(active)) if active else ''
         o.decks = other
示例#16
0
def bulk_delete(
        filesystem_id: str,
        items_selected: List[Union[Submission, Reply]]) -> werkzeug.Response:
    for item in items_selected:
        delete_file_object(item)

    flash(
        ngettext("Submission deleted.",
                 "{num} submissions deleted.".format(num=len(items_selected)),
                 len(items_selected)), "notification")
    return redirect(url_for('col.col', filesystem_id=filesystem_id))
示例#17
0
def prettify_time_ago(t):
    """
    Converts seconds to a meaningful string.

    INPUT

    - t -- time in seconds

    """
    if t < 60:
        s = int(t)
        return ngettext('%(num)d second', '%(num)d seconds', s)
    if t < 3600:
        m = int(t/60)
        return ngettext('%(num)d minute', '%(num)d minutes', m)
    if t < 3600*24:
        h = int(t/3600)
        return ngettext('%(num)d hour', '%(num)d hours', h)
    d = int(t/(3600*24))
    return ngettext('%(num)d day', '%(num)d days', d)
示例#18
0
 def check_username_acceptable(cls, username: str) -> None:
     if len(username) < cls.MIN_USERNAME_LEN:
         raise InvalidUsernameException(
             ngettext(
                 "Must be at least {num} character long.",
                 "Must be at least {num} characters long.",
                 cls.MIN_USERNAME_LEN,
             ).format(num=cls.MIN_USERNAME_LEN))
     if username in cls.INVALID_USERNAMES:
         raise InvalidUsernameException(
             gettext("This username is invalid because it is reserved "
                     "for internal use by the software."))
示例#19
0
def bulk_delete(filesystem_id, items_selected):
    for item in items_selected:
        item_path = store.path(filesystem_id, item.filename)
        worker.enqueue(srm, item_path)
        db_session.delete(item)
    db_session.commit()

    flash(ngettext("Submission deleted.",
                   "{num} submissions deleted.".format(
                       num=len(items_selected)),
                   len(items_selected)), "notification")
    return redirect(url_for('col.col', filesystem_id=filesystem_id))
示例#20
0
    def calculate_date_difference(first_date: str, second_date: str) -> str:

        time = relativedelta(
            parse_datetime(second_date),
            parse_datetime(first_date),
        )

        if time.years:
            year_string: str = ngettext("{number_of_years} year",
                                        "{number_of_years} years", time.years)
            return year_string.format(number_of_years=time.years)

        if time.months:
            month_string: str = ngettext("{number_of_months} month",
                                         "{number_of_months} months",
                                         time.months)
            return month_string.format(number_of_months=time.months)

        day_string: str = ngettext("{number_of_days} day",
                                   "{number_of_days} days", time.days)
        return day_string.format(number_of_days=time.days)
示例#21
0
 def bulk_delete(self, **kwargs: Any) -> Response:
     """Delete bulk Datasets
     ---
     delete:
       description: >-
         Deletes multiple Datasets in a bulk operation.
       parameters:
       - in: query
         name: q
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/get_delete_ids_schema'
       responses:
         200:
           description: Dataset bulk delete
           content:
             application/json:
               schema:
                 type: object
                 properties:
                   message:
                     type: string
         400:
           $ref: '#/components/responses/400'
         401:
           $ref: '#/components/responses/401'
         403:
           $ref: '#/components/responses/403'
         404:
           $ref: '#/components/responses/404'
         422:
           $ref: '#/components/responses/422'
         500:
           $ref: '#/components/responses/500'
     """
     item_ids = kwargs["rison"]
     try:
         BulkDeleteDatasetCommand(g.user, item_ids).run()
         return self.response(
             200,
             message=ngettext(
                 "Deleted %(num)d dataset",
                 "Deleted %(num)d datasets",
                 num=len(item_ids),
             ),
         )
     except DatasetNotFoundError:
         return self.response_404()
     except DatasetForbiddenError:
         return self.response_403()
     except DatasetBulkDeleteFailedError as ex:
         return self.response_422(message=str(ex))
示例#22
0
    def _get_message(self, _zipcode: Zipcode) -> MessageResponse:
        response = (
            MessageResponse()
            .write(self.client.get_current_pm25_level().description)
            .write("")
        )

        num_desired = 3
        recommended_zipcodes = self.client.get_recommendations(num_desired)
        if recommended_zipcodes:
            response.write(
                gettext("Here are the closest places with better air quality:")
            )
            conversion_factor = self.client.conversion_factor
            for recommendation in recommended_zipcodes:
                response.write(
                    gettext(
                        " - %(city)s %(zipcode)s: %(pm25_level)s (%(distance)s mi)",
                        city=recommendation.city.name,
                        zipcode=recommendation.zipcode,
                        pm25_level=recommendation.get_pm25_level(
                            conversion_factor
                        ).display.upper(),
                        distance=round(
                            kilometers_to_miles(
                                recommendation.distance(self.client.zipcode)
                            ),
                            ndigits=1,
                        ),  # TODO: Make this based on locale
                    )
                )
            response.newline()

        response.write(
            ngettext(
                "Average PM2.5 from %(num)d sensor near %(zipcode)s is %(pm25)s ug/m^3.",
                "Average PM2.5 from %(num)d sensors near %(zipcode)s is %(pm25)s ug/m^3.",
                self.client.zipcode.num_sensors,
                zipcode=self.client.zipcode.zipcode,
                pm25=self.client.get_current_pm25(),
            )
        )

        self.client.log_event(
            EventType.DETAILS,
            zipcode=self.client.zipcode.zipcode,
            recommendations=[r.zipcode for r in recommended_zipcodes],
            pm25=self.client.get_current_pm25(),
            num_sensors=self.client.zipcode.num_sensors,
        )

        return response
示例#23
0
文件: api.py 项目: ws1993/superset
 def bulk_delete(self, **kwargs: Any) -> Response:
     """Delete bulk Annotation layers
     ---
     delete:
       description: >-
         Deletes multiple annotation in a bulk operation.
       parameters:
       - in: path
         schema:
           type: integer
         name: pk
         description: The annotation layer pk for this annotation
       - in: query
         name: q
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/get_delete_ids_schema'
       responses:
         200:
           description: Annotations bulk delete
           content:
             application/json:
               schema:
                 type: object
                 properties:
                   message:
                     type: string
         401:
           $ref: '#/components/responses/401'
         404:
           $ref: '#/components/responses/404'
         422:
           $ref: '#/components/responses/422'
         500:
           $ref: '#/components/responses/500'
     """
     item_ids = kwargs["rison"]
     try:
         BulkDeleteAnnotationCommand(g.user, item_ids).run()
         return self.response(
             200,
             message=ngettext(
                 "Deleted %(num)d annotation",
                 "Deleted %(num)d annotations",
                 num=len(item_ids),
             ),
         )
     except AnnotationNotFoundError:
         return self.response_404()
     except AnnotationBulkDeleteFailedError as ex:
         return self.response_422(message=str(ex))
示例#24
0
def col_delete(cols_selected):
    """deleting multiple collections from the index"""
    if len(cols_selected) < 1:
        flash(gettext("No collections selected for deletion."), "error")
    else:
        for filesystem_id in cols_selected:
            delete_collection(filesystem_id)
        num = len(cols_selected)
        flash(
            ngettext('{num} collection deleted', '{num} collections deleted',
                     num).format(num=num), "notification")

    return redirect(url_for('main.index'))
示例#25
0
    def _build_range_length_error(period_object):
        error_message = ""
        if "years" in period_object:
            error_message = ngettext(
                "%(num)s year", "%(num)s years", period_object["years"]
            )
        if "months" in period_object:
            message_addition = ngettext(
                "%(num)s month", "%(num)s months", period_object["months"]
            )
            error_message += (
                message_addition if error_message == "" else ", " + message_addition
            )
        if "days" in period_object:
            message_addition = ngettext(
                "%(num)s day", "%(num)s days", period_object["days"]
            )
            error_message += (
                message_addition if error_message == "" else ", " + message_addition
            )

        return error_message
示例#26
0
def push_coin_notification(sender, receiver, post, amount):
    message = ngettext(
        """<a href="%(profile_url)s">%(username)s</a> gives %(num)s coin to your post
           <a href="%(post_url)s">%(post_title)s</a>.""",
        """<a href="%(profile_url)s">%(username)s</a> gives %(num)s coins to your post
           <a href="%(post_url)s">%(post_title)s</a>.""",
        profile_url=sender.profile_url(),
        username=sender.username,
        post_url=post.url(),
        post_title=post.title,
        num=amount,
    )
    Notification(message=message, receiver=receiver).push()
示例#27
0
def calculate_years_difference(from_str, to_str):
    if from_str is None or to_str is None:
        raise Exception(
            'Valid date(s) not passed to calculate_years_difference filter')

    to_date = datetime.now() if to_str == 'now' else convert_to_datetime(
        to_str)
    from_date = convert_to_datetime(from_str)
    difference = relativedelta.relativedelta(to_date, from_date)
    year_string = flask_babel.ngettext('%(num)s year', '%(num)s years',
                                       difference.years)

    return year_string
示例#28
0
def col_delete(cols_selected):
    """deleting multiple collections from the index"""
    if len(cols_selected) < 1:
        flash(gettext("No collections selected for deletion."), "error")
    else:
        for filesystem_id in cols_selected:
            delete_collection(filesystem_id)
        num = len(cols_selected)
        flash(ngettext('{num} collection deleted', '{num} collections deleted',
                       num).format(num=num),
              "notification")

    return redirect(url_for('main.index'))
示例#29
0
def display_time(seconds, granularity=2):
    """Time convert to other units."""
    results = []
    if granularity <= 0:
        granularity = 1

    intervals = (
        1*60*60*24*7*4*12,
        1*60*60*24*7*4,
        1*60*60*24*7,
        1*60*60*24,
        1*60*60,
        1*60,
        1,
    )

    for count in intervals:
        value = seconds // count
        if value:
            seconds -= value * count
        results.append(value)

    intervals = []
    if results[0]:
        intervals.append(
            ngettext(u'%(num)s year', u'%(num)s years', results[0])
        ),
    if results[1]:
        intervals.append(
            ngettext(u'%(num)s month', u'%(num)s months', results[1])
        ),
    if results[2]:
        intervals.append(
            ngettext(u'%(num)s week', u'%(num)s weeks', results[2])
        ),
    if results[3]:
        intervals.append(
            ngettext(u'%(num)s day', u'%(num)s days', results[3])
        ),
    if results[4]:
        intervals.append(
            ngettext(u'%(num)s hour', u'%(num)s hours', results[4])
        ),
    if results[5]:
        intervals.append(
            ngettext(u'%(num)s minute', u'%(num)s minutes', results[5])
        ),
    if results[6]:
        intervals.append(
            ngettext(u'%(num)s second', u'%(num)s seconds', results[6])
        ),

    return intervals[:granularity]
示例#30
0
文件: routes.py 项目: e2jk/syncboom
def account(edit_element=None):
    trello_username = current_user.trello_username
    if not edit_element:
        return render_template('account.html',
                               title=_('Account'),
                               trello_username=trello_username)
    else:
        num_mappings = None
        original_value = getattr(current_user, edit_element) \
            if hasattr(current_user, edit_element) else ""
        form = makeAccountEditForm(edit_element, original_value)
        if form.validate_on_submit():
            redirect_url = url_for('main.account')
            if edit_element == "password":
                current_user.set_password(form.password.data)
                flash(_('Your %s has been updated.' % edit_element))
            elif edit_element == "trello":
                # Delete current Trello token
                current_user.trello_token = None
                # Delete all the mappings the user currently has, since they
                # have been created with the old Trello key we just removed.
                for m in current_user.mappings:
                    db.session.delete(m)
                # Redirect to Trello for new pairing
                redirect_url = get_trello_authorizing_url()
            else:
                setattr(current_user, edit_element,
                        getattr(form, edit_element).data.lower())
                flash(_('Your %s has been updated.' % edit_element))
            db.session.commit()
            return redirect(redirect_url)
        elif request.method == 'GET':
            if edit_element == "trello":
                form.submit.label.text = _('Unlink and continue to Trello')
                num_mappings = len(current_user.get_mappings())
                if num_mappings:
                    form.trello.label.text = ngettext(
                        'OK, unlink my Trello account and delete my mapping',
                        'OK, unlink my Trello account and delete my ' \
                            '%(num_mappings)d mappings',
                        num_mappings,
                        num_mappings=num_mappings)
            else:
                getattr(form, edit_element).data = original_value.lower()
        return render_template('account_edit.html',
                               title=_('Edit %s' % edit_element),
                               form=form,
                               edit_element=edit_element,
                               trello_username=trello_username,
                               num_mappings=num_mappings)
示例#31
0
def col_delete(cols_selected: List[str]) -> werkzeug.Response:
    """deleting multiple collections from the index"""
    if len(cols_selected) < 1:
        flash(gettext("No collections selected for deletion."), "error")
    else:
        now = datetime.datetime.utcnow()
        sources = Source.query.filter(Source.filesystem_id.in_(cols_selected))
        sources.update({Source.deleted_at: now}, synchronize_session="fetch")
        db.session.commit()

        num = len(cols_selected)
        flash(
            ngettext('{num} collection deleted', '{num} collections deleted',
                     num).format(num=num), "notification")

    return redirect(url_for('main.index'))
示例#32
0
 def _update_issues_in_progress(self):
     issues = []
     if 'in_progress_id' in self._config:
         issue_state = self._redmine.issue_status.get(self._config['in_progress_id'])
         for issue in issue_state.issues:
             days_since_update = (datetime.now() - issue.updated_on).days
             issues.append({
                 'subject': issue.subject,
                 'url': self._config['url'] + 'issues/' + str(issue.id),
                 'done_ratio': issue.done_ratio,
                 'updated': issue.updated_on,
                 'days_since_update': ngettext('{num} day ago', '{num} days ago', days_since_update).format(
                     num=days_since_update) if days_since_update > 0 else None,
                 'days_since_update_color': Tasks.IN_PROGRESS_DAY_COLORS[max(k for k in Tasks.IN_PROGRESS_DAY_COLORS if k <= days_since_update)],
             })
     self.issues_in_progress = sorted(issues, key=lambda x: x['updated'])
示例#33
0
 def bulk_delete(self, **kwargs: Any) -> Response:  # pylint: disable=arguments-differ
     """Delete bulk Saved Queries
     ---
     delete:
       description: >-
         Deletes multiple saved queries in a bulk operation.
       parameters:
       - in: query
         name: q
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/get_delete_ids_schema'
       responses:
         200:
           description: Saved queries bulk delete
           content:
             application/json:
               schema:
                 type: object
                 properties:
                   message:
                     type: string
         401:
           $ref: '#/components/responses/401'
         404:
           $ref: '#/components/responses/404'
         422:
           $ref: '#/components/responses/422'
         500:
           $ref: '#/components/responses/500'
     """
     item_ids = kwargs["rison"]
     try:
         BulkDeleteSavedQueryCommand(g.user, item_ids).run()
         return self.response(
             200,
             message=ngettext(
                 "Deleted %(num)d saved query",
                 "Deleted %(num)d saved queries",
                 num=len(item_ids),
             ),
         )
     except SavedQueryNotFoundError:
         return self.response_404()
     except SavedQueryBulkDeleteFailedError as ex:
         return self.response_422(message=str(ex))
示例#34
0
def login():
    if current_user.is_authenticated:
        flash(_('You were already authenticated as %(name)s.',
                name=b(current_user.name)), 'info')
        if session['preferences']:
            session.pop('preferences', None)
        if session['locale']:
            session.pop('locale', None)

        logout_user()

    form = LoginForm()

    if not current_app.config['RUNE_AUTH_LOGIN_REMEMBER']:
        form.remember_me = None

    if form.validate_on_submit():
        _fails = 0

        user = User.query.filter_by(username=form.username.data).first()
        if user is None:
            flash(_('Invalid username or password.'), 'error')
            return redirect(url_for('auth.login'))

        _fails = user.failed_attempts

        if not user.verify_password(form.password.data):
            flash(_('Invalid username or password.'), 'error')
            return redirect(url_for('auth.login'))

        if _fails > 0:
            flash(ngettext('You have %(num)d failed login attempt.',
                           'You have %(num)d failed login attempts.',
                           num=_fails),
                  'warning')

        login_user(user)

        session['locale'] = user.locale
        session['preferences'] = {}

        for preference in user.preferences:
            session['preferences'][preference.name] = preference.value

        return redirect(request.args.get('next') or url_for('main.index'))

    return render_template('auth/routes.login.html.j2', form=form)
示例#35
0
def validate_user(username, password, token, error_message=None):
    """
    Validates the user by calling the login and handling exceptions
    :param username: Username
    :param password: Password
    :param token: Two-factor authentication token
    :param error_message: Localized error message string to use on failure
    :return: Journalist user object if successful, None otherwise.
    """
    try:
        return Journalist.login(username, password, token)
    except (InvalidUsernameException,
            BadTokenException,
            WrongPasswordException,
            LoginThrottledException) as e:
        current_app.logger.error("Login for '{}' failed: {}".format(
            username, e))
        if not error_message:
            error_message = gettext('Login failed.')
        login_flashed_msg = error_message

        if isinstance(e, LoginThrottledException):
            login_flashed_msg += " "
            period = Journalist._LOGIN_ATTEMPT_PERIOD
            # ngettext is needed although we always have period > 1
            # see https://github.com/freedomofpress/securedrop/issues/2422
            login_flashed_msg += ngettext(
                "Please wait at least {seconds} second "
                "before logging in again.",
                "Please wait at least {seconds} seconds "
                "before logging in again.", period).format(seconds=period)
        else:
            try:
                user = Journalist.query.filter_by(
                    username=username).one()
                if user.is_totp:
                    login_flashed_msg += " "
                    login_flashed_msg += gettext(
                        "Please wait for a new two-factor token"
                        " before trying again.")
            except:
                pass

        flash(login_flashed_msg, "error")
        return None
示例#36
0
def download(
    zip_basename: str,
    submissions: List[Union[Submission, Reply]],
    on_error_redirect: Optional[str] = None,
) -> werkzeug.Response:
    """Send client contents of ZIP-file *zip_basename*-<timestamp>.zip
    containing *submissions*. The ZIP-file, being a
    :class:`tempfile.NamedTemporaryFile`, is stored on disk only
    temporarily.

    :param str zip_basename: The basename of the ZIP-file download.

    :param list submissions: A list of :class:`models.Submission`s to
                             include in the ZIP-file.
    """
    try:
        zf = Storage.get_default().get_bulk_archive(submissions,
                                                    zip_directory=zip_basename)
    except FileNotFoundError:
        flash(
            ngettext(
                "Your download failed because the file could not be found. An admin can find "
                + "more information in the system and monitoring logs.",
                "Your download failed because a file could not be found. An admin can find "
                + "more information in the system and monitoring logs.",
                len(submissions),
            ),
            "error",
        )
        if on_error_redirect is None:
            on_error_redirect = url_for("main.index")
        return redirect(on_error_redirect)

    attachment_filename = "{}--{}.zip".format(
        zip_basename,
        datetime.now(timezone.utc).strftime("%Y-%m-%d--%H-%M-%S"))

    mark_seen(submissions, g.user)

    return send_file(
        zf.name,
        mimetype="application/zip",
        download_name=attachment_filename,
        as_attachment=True,
    )
示例#37
0
 def __init__(self, competition):
     self.competition = competition
     self.competitions = [self.competition]
     decks = competition.decks
     active_runs = [d for d in decks if d.is_in_current_run()]
     self.decks = [d for d in decks if d not in active_runs]
     self.hide_source = True
     if competition.type == 'League':
         self.active_runs = ngettext('%(num)d active league run',
                                     '%(num)d active league runs',
                                     len(active_runs))
         self.show_omw = True
         self.hide_top8 = True
         self.league_info_url = url_for('league')
         leaderboard = {}
         for d in competition.decks:
             if d.banned:
                 continue
             bonus = 0
             if d.wins >= 5:
                 bonus = 1
             points = d.wins + bonus
             if d.person_id not in leaderboard:
                 leaderboard[d.person_id] = Container({
                     'person': d.person,
                     'person_id': d.person_id,
                     'points': 0,
                     'played': 0,
                     'retirements': 0
                 })
             leaderboard[d.person_id]['points'] += points
             leaderboard[
                 d.person_id]['played'] += d.wins + d.draws + d.losses
             leaderboard[
                 d.person_id]['retirements'] += 1 if d.retired else 0
         if len(leaderboard) > 0:
             self.has_leaderboard = True
             self.leaderboard = sorted(
                 leaderboard.values(),
                 key=lambda k:
                 (k['points'], k['played'], -k['retirements']),
                 reverse=True)
             self.leaderboards = [self.leaderboard
                                  ]  # Will be prepared in View.
示例#38
0
def bulk_delete(
        filesystem_id: str,
        items_selected: List[Union[Submission, Reply]]) -> werkzeug.Response:
    deletion_errors = 0
    for item in items_selected:
        try:
            delete_file_object(item)
        except ValueError:
            deletion_errors += 1

    flash(
        ngettext("Submission deleted.",
                 "{num} submissions deleted.".format(num=len(items_selected)),
                 len(items_selected)), "notification")
    if deletion_errors > 0:
        current_app.logger.error(
            "Disconnected submission entries (%d) were detected",
            deletion_errors)
    return redirect(url_for('col.col', filesystem_id=filesystem_id))
示例#39
0
def top(page):
    period = request.args.get('period')
    if period and period.isdigit():
        period = int(period)
    else:
        period = 0

    objects = Story.bl.select_top(period)
    objects = objects.prefetch(Story.characters, Story.contributors, StoryContributor.user, Story.tags, StoryTag.tag, Tag.category)

    page_obj = Paginator(
        page,
        objects.count(),
        per_page=current_app.config['STORIES_COUNT']['stream'],
        view_args={'period': period} if period > 0 else None,
    )

    stories = page_obj.slice_or_404(objects)

    if period == 7:
        page_title = gettext('Top stories for the week')
    elif period == 30:
        page_title = gettext('Top stories for the month')
    elif period == 365:
        page_title = gettext('Top stories for the year')
    elif period == 0:
        page_title = gettext('Top stories for all time')
    else:
        page_title = ngettext('Top stories in %(num)d day', 'Top stories in %(num)d days', period)

    data = dict(
        stories=stories,
        page_obj=page_obj,
        count=objects.count(),
        page_title=page_title,
        period=period,
    )
    data.update(cached_lists([x.id for x in stories]))

    return render_template('stream/stories_top.html', **data)
示例#40
0
def feed_stories_top():
    period = request.args.get('period', 0)
    try:
        period = int(period)
    except ValueError:
        period = 0

    if period == 7:
        title = gettext('Top stories for the week')
    elif period == 30:
        title = gettext('Top stories for the month')
    elif period == 365:
        title = gettext('Top stories for the year')
    elif period == 0:
        title = gettext('Top stories for all time')
    else:
        title = ngettext('Top stories in %(num)d day', 'Top stories in %(num)d days', period)

    feed = AtomFeed(
        title='{} — {}'.format(title, sitename()),
        subtitle='Топ рассказов',
        feed_url=request.url,
        url=request.url_root
    )

    count = current_app.config['RSS'].get('stories', 20)
    stories = Story.bl.select_top(period)[:count]
    for story in stories:
        author = story.authors[0]
        feed.add(
            story.title,
            Markup(story.summary).striptags(),
            content_type='text',
            author=author.username,
            url=url_for('story.view', pk=story.id, _external=True),
            updated=story.updated,
            published=story.first_published_at or story.date
        )
    return feed.get_response()