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'
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})
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
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))
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)
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))
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')
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
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)
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))
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))
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)
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))
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)
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
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))
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)
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."))
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))
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)
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))
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
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))
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'))
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
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()
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
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'))
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]
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)
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'))
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'])
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))
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)
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
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, )
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.
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))
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)
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()