def massmail(self): """ Send a massmail to all users in the system. It also stores the sent mail and its recipients in the database to keep a permanent record of sent messages. """ form = MassMailForm(self.request.POST, csrf_context=self.request) if not form.from_.data: settings = self.request.registry.settings form.from_.data = settings["mail.default_sender"] mail_query = DBSession.query(MassMail) page = self.page(mail_query) retparams = {"form": form, "items": page.items, "page": page} if self.request.method == "POST": if not form.validate(): return retparams teams = get_active_teams() # Create a record to keep track of all sent mails mail_record = MassMail() form.populate_obj(mail_record) recipients = [team.email for team in teams] mail_record.recipients = recipients mailer = get_mailer(self.request) message = Message( subject=mail_record.subject, bcc=mail_record.recipients, body=mail_record.message, sender=mail_record.from_, ) DBSession.add(mail_record) mailer.send(message) self.request.session.flash("Mass mail sent to all %d active users" % len(recipients)) return HTTPFound(location=self.request.route_url("admin_massmail")) return retparams
def submissions_edit(self): # Prepare parameters form = SubmissionForm(self.request.POST, csrf_context=self.request) submissions = get_submissions() page = self.page(submissions) redirect = self.redirect("admin_submissions", page.page) # Cancel button pressed? if not form.submit.data: return redirect is_new = not bool(form.challenge.data and form.team.data) # Form errors? if not form.validate(): return self._list_retparams(page, form, is_new=is_new) # New item or existing one? try: submission = ( DBSession.query(Submission) .filter(Submission.challenge_id == form.challenge.data.id) .filter(Submission.team_id == form.team.data.id) .one() ) self.request.session.flash("Submission edited!") except NoResultFound: submission = Submission() DBSession.add(submission) self.request.session.flash("Submission added!") # Transfer edits into databse form.populate_obj(submission) return redirect
def database(request, testapp): dbsession = DBSession() Base.metadata.create_all(bind=dbsession.connection()) if not dbsession.query(Settings).all(): dbsession.add(Settings()) def _drop(): conn = dbsession.connection() Base.metadata.drop_all(bind=conn) # TODO: Why do we have to use this literally? # If fixed test against MySQL *and* Postgres! conn.execute("COMMIT") request.addfinalizer(_drop)
def register_ip(event): if ("test-login" in event.request.session and event.request.session["test-login"] or event.request.path.startswith('/static')): return None team_id = event.request.authenticated_userid t = transaction.savepoint() if not team_id: return ip = unicode(event.request.client_addr) try: DBSession.add(TeamIP(team_id=team_id, ip=ip)) DBSession.flush() except IntegrityError: t.rollback()
def install(settings, cfg_file, test_data=False): """ Installs the application. Only required to be called once per installation. """ dbsession = DBSession() transaction.begin() try: install_alembic_table(cfg_file) Base.metadata.create_all(bind=dbsession.connection()) create_country_list(dbsession) if test_data: install_test_data(dbsession, settings) if not dbsession.query(Settings).all(): dbsession.add(Settings()) for dyn_mod in dynamic_challenges.registry.values(): dyn_mod.install(dbsession.connection()) except: transaction.abort() raise else: transaction.commit()
def _admin_edit(self, route_name, FormClass, DatabaseClass, title): """ A generic function for a view that is invoked after an edit (or add) has been performed. It is separate from that of :meth:`AdminView._admin_list` to keep the code cleaner. It has the same parameters and return types but can only be invoked as a ``POST``. """ # We don't accept GET or others here assert self.request.method == "POST" # Prepare parameters form = FormClass(self.request.POST, csrf_context=self.request) page = self.page(self.items(DatabaseClass)) redirect = self.redirect(route_name, page.page) # Cancel button pressed? if not form.submit.data: return redirect # Form errors? if not form.validate(): return self._list_retparams(page, form) # New item or existing one? if not form.id.data: db_item = DatabaseClass() DBSession.add(db_item) self.request.session.flash("%s added!" % title) else: db_item = DBSession.query(DatabaseClass).filter(DatabaseClass.id == form.id.data).one() self.request.session.flash("%s edited!" % title) # Transfer edits into database form.populate_obj(db_item) if db_item.id == "": # Safe measure to ensure a clean item ID db_item.id = None return redirect
def register_team(form, request): """ Create a new team from a form and send a confirmation email. Args: ``form``: A filled out :class:`fluxscoreboard.forms.front.RegisterForm`. ``request``: The corresponding request. Returns: The :class:`Team` that was created. """ team = Team(name=form.name.data, email=form.email.data, password=form.password.data, country=form.country.data, timezone=form.timezone.data, size=form.size.data, ) DBSession.add(team) DBSession.flush() send_activation_mail(team, request) return team
def check_submission(challenge, solution, team, settings): """ Check a solution for a challenge submitted by a team and add it to the database if it was correct. Args: ``challenge``: An instance of :class:`Challenge`, the challenge to check the solution for. ``solution``: A string, the proposed solution for the challenge. ``team``: Team that submitted the solution. Returns: A tuple of ``(result, msg)``. ``result`` indicates whether the solution was accpeted (and added to the database) or not. The message returns a string with either a result (if ``result == False``) or a congratulations message. """ # Perform all checks that filter out invalid submissions if settings.submission_disabled: return False, "Submission is currently disabled" if not settings.archive_mode and now() > settings.ctf_end_date: return False, "The CTF is over, no more solutions can be submitted." if not challenge.online: return False, "Challenge is offline." if challenge.manual: return False, "Credits for this challenge will be given manually." if challenge.dynamic: return False, "The challenge is dynamic, no submission possible." # help faggots solution = solution.strip() if solution.startswith('flag{'): solution = solution[5:-1] if challenge.solution != solution: return False, "Solution incorrect." # After this, the solution is correct and we can return True if settings.archive_mode: return True, ("Congratulations: That was the correct solution! " "However, since the scoreboard is in archive mode, you " "will not be awarded any points.") query = (DBSession.query(Submission.team_id). filter(Submission.challenge_id == challenge.id)) submissions = [id_ for id_, in query] if team.id in submissions: return False, "Already solved." solved_count = len(submissions) first_blood_pts, place_msg = first_blood_map.get(solved_count, (0, None)) if place_msg is not None: msg = 'Congratulations: You solved this challenge as %s!' % place_msg else: msg = 'Congratulations: That was the correct solution!' msg += (' How did you like this challenge? Please provide some feedback ' 'in the form below.') submission = Submission(additional_pts=first_blood_pts) submission.team_id = team.id submission.challenge = challenge DBSession.add(submission) team.base_score += challenge.base_points + first_blood_pts team.bonus_score += challenge.points - challenge.base_points return True, msg
def challenge(self): """ A view of a single challenge. The query is very similar to that of :meth:`challenges` with the limitation that only one challenge is fetched. Additionally, this page displays a form to enter the solution of that challenge and fetches a list of announcements for the challenge. """ challenge_id = int(self.request.matchdict["id"]) team_id = self.request.authenticated_userid team_solved_subquery = get_team_solved_subquery(team_id) try: challenge, is_solved = ( DBSession.query(Challenge, team_solved_subquery). filter(Challenge.id == challenge_id). filter(Challenge.published).one() ) except NoResultFound: self.request.session.flash("Challenge not found or published.") return HTTPFound(location=self.request.route_url('challenges')) form = SolutionSubmitForm(self.request.POST, csrf_context=self.request) retparams = {'challenge': challenge, 'form': form, 'is_solved': is_solved, } # solved or after CTF feedback_obj = None if is_solved or (CTF_ENDED, True) == self.current_state: feedback_obj = ( DBSession.query(Feedback). filter(Feedback.team_id == self.request.team.id). filter(Feedback.challenge_id == challenge.id). first()) if not feedback_obj: feedback_obj = Feedback(team_id=self.request.team.id, challenge_id=challenge.id) DBSession.add(feedback_obj) retparams['feedback'] = FeedbackForm( self.request.POST, obj=feedback_obj, csrf_context=self.request) if self.request.method == 'POST': if 'submit_feedback' in self.request.POST: if not retparams['feedback'].validate(): return retparams if feedback_obj: retparams['feedback'].populate_obj(feedback_obj) self.request.session.flash( 'Thanks for your feedback. You can edit it at any ' 'point.') else: if not form.validate(): return retparams is_solved, msg = check_submission( challenge, form.solution.data, self.request.team, self.request.settings) self.request.session.flash(msg, 'success' if is_solved else 'error') return HTTPFound(location=self.request.route_url('challenge', id=challenge.id) ) return retparams