def get_session(cls, uuid, user=None, anon_user=None): ues = cls.query.filter_by(uuid=uuid).one_or_none() if uuid else None # We no longer hard-link sessions to users, so this is commented out: # require_one_of(user=user, anon_user=anon_user) # ues = cls.query.filter_by( # user=user, anon_user=anon_user).filter( # cls.ended_at == None).order_by(cls.created_at.desc()).first() # NOQA if ues: # Has this session been inactive for over half an hour? Close it, # mark as closed when last active. if ues.active_at < utcnow() - timedelta(minutes=30): ues.ended_at = ues.active_at # The attribute change goes into the database session's cache, # so we can safely discard the local variable assignment here. ues = None # Campaign parameters changed? End the session again. See Google's documentation for reasoning # https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCampaigns if ues is not None: for param in ('utm_source', 'utm_medium', 'utm_term', 'utm_content', 'utm_id', 'utm_campaign', 'gclid'): pvalue = request.args.get(param, '')[:250] or None if pvalue and pvalue != getattr(ues, param): ues.ended_at = utcnow() ues = None break if not ues: ues = cls.new_from_request(request) ues.user = user ues.anon_user = anon_user db.session.add(ues) ues.active_at = utcnow() return ues
def reset_campaign_views(): # Periodic job (see manage.py) live_campaigns = Campaign.query.filter(Campaign.state.is_live).options( db.load_only(Campaign.id)) CampaignView.query.filter( CampaignView.campaign_id.in_(live_campaigns), CampaignView.last_viewed_at < utcnow() - timedelta(days=30), ).update( { 'dismissed': False, 'session_count': 0, 'reset_at': db.func.utcnow() }, synchronize_session=False, ) CampaignAnonView.query.filter( CampaignAnonView.campaign_id.in_(live_campaigns), CampaignAnonView.last_viewed_at < utcnow() - timedelta(days=30), ).update( { 'dismissed': False, 'session_count': 0, 'reset_at': db.func.utcnow() }, synchronize_session=False, ) db.session.commit()
def request_timestamp() -> datetime: """Return a consistent UTC timestamp for the lifetime of the ongoing request.""" if not g: return utcnow() ts = getattr(g, 'request_timestamp', None) if ts is None: ts = utcnow() g.request_timestamp = ts return ts
def request_timestamp(): """ Return a UTC timestamp for the request """ if not g: return utcnow() ts = getattr(g, 'request_timestamp', None) if ts is None: ts = utcnow() g.request_timestamp = ts return ts
def regenerate_line_item(order, original_line_item, updated_line_item_tup, line_item_seq): """ Marks the original line item as `void`, and returns a new line item object with the updated attributes """ original_line_item.make_void() item = Item.query.get(updated_line_item_tup.item_id) if updated_line_item_tup.discount_policy_id: policy = DiscountPolicy.query.get( updated_line_item_tup.discount_policy_id) else: policy = None if updated_line_item_tup.discount_coupon_id: coupon = DiscountCoupon.query.get( updated_line_item_tup.discount_coupon_id) else: coupon = None return LineItem(order=order, item=item, discount_policy=policy, previous=original_line_item, status=LINE_ITEM_STATUS.CONFIRMED, line_item_seq=line_item_seq, discount_coupon=coupon, ordered_at=utcnow(), base_amount=updated_line_item_tup.base_amount, discounted_amount=updated_line_item_tup.discounted_amount, final_amount=updated_line_item_tup.base_amount - updated_line_item_tup.discounted_amount)
def connect(self, puk, key): """Scan verification""" ticket_participant = TicketParticipant.query.filter_by( puk=puk, key=key).first() if not ticket_participant: return make_response( jsonify(status='error', message="Attendee details not found"), 404) project = ticket_participant.project if project.schedule_end_at: if (midnight_to_utc(project.schedule_end_at + timedelta(days=1), project.timezone) < utcnow()): return make_response( jsonify(status='error', message=_("This project has concluded")), 403, ) try: contact_exchange = ContactExchange( user=current_auth.actor, ticket_participant=ticket_participant) db.session.add(contact_exchange) db.session.commit() except IntegrityError: current_app.logger.warning("Contact already scanned") db.session.rollback() return jsonify(contact=contact_details(ticket_participant)) else: return make_response( jsonify(status='error', message="Unauthorized contact exchange"), 403)
def jsonify_new_price(data_dict): item = data_dict['item'] price_form = PriceForm(parent=item) if request.method == 'GET': return jsonify(form_template=render_form(form=price_form, title="New price", submit="Save", with_chrome=False).get_data( as_text=True)) if price_form.validate_on_submit(): price = Price(item=item) price_form.populate_obj(price) price.title = "{item_name}-price-{datetime}".format( item_name=item.name, datetime=json_date_format(utcnow())) if not price.name: price.make_name() db.session.add(price) db.session.commit() return api_success( result={'price': dict(price.current_access())}, doc=_("New price created"), status_code=201, ) return api_error( message=_("There was a problem with creating the price"), status_code=400, errors=price_form.errors, )
def test_cfp_state_draft(test_db, new_organization, new_project): assert new_project.cfp_start_at is None assert new_project.state.DRAFT assert new_project.cfp_state.NONE assert not new_project.cfp_state.DRAFT assert new_project in new_organization.profile.draft_projects new_project.open_cfp() test_db.session.commit() assert new_project.cfp_state.PUBLIC assert new_project.cfp_start_at is None assert new_project.cfp_state.DRAFT assert new_project in new_organization.profile.draft_projects new_project.cfp_start_at = utcnow() test_db.session.commit() assert new_project.cfp_start_at is not None assert not new_project.cfp_state.DRAFT assert (new_project in new_organization.profile.draft_projects ) # because project state is still draft new_project.publish() test_db.session.commit() assert not new_project.cfp_state.DRAFT assert not new_project.state.DRAFT assert new_project not in new_organization.profile.draft_projects
def regenerate_line_item(order, original_line_item, updated_line_item_tup, line_item_seq): """Update a line item by marking the original as void and creating a replacement.""" original_line_item.make_void() item = Item.query.get(updated_line_item_tup.item_id) if updated_line_item_tup.discount_policy_id: policy = DiscountPolicy.query.get( updated_line_item_tup.discount_policy_id) else: policy = None if updated_line_item_tup.discount_coupon_id: coupon = DiscountCoupon.query.get( updated_line_item_tup.discount_coupon_id) else: coupon = None return LineItem( order=order, item=item, discount_policy=policy, previous=original_line_item, status=LINE_ITEM_STATUS.CONFIRMED, line_item_seq=line_item_seq, discount_coupon=coupon, ordered_at=utcnow(), base_amount=updated_line_item_tup.base_amount, discounted_amount=updated_line_item_tup.discounted_amount, final_amount=updated_line_item_tup.base_amount - updated_line_item_tup.discounted_amount, )
def lastuser_cookie(response): """ Save lastuser login cookie and hasuser JS-readable flag cookie. """ if request_has_auth() and hasattr(current_auth, 'cookie'): expires = utcnow() + timedelta(days=365) response.set_cookie( 'lastuser', value=lastuser_oauth.serializer.dumps(current_auth.cookie, header_fields={'v': 1}), max_age=31557600, # Keep this cookie for a year. expires=expires, # Expire one year from now. domain=current_app.config.get( 'LASTUSER_COOKIE_DOMAIN'), # Place cookie in master domain. secure=current_app. config['SESSION_COOKIE_SECURE'], # HTTPS cookie if session is too. httponly=True) # Don't allow reading this from JS. response.set_cookie( 'hasuser', value='1' if current_auth.is_authenticated else '0', max_age=31557600, # Keep this cookie for a year. expires=expires, # Expire one year from now. secure=current_app. config['SESSION_COOKIE_SECURE'], # HTTPS cookie if session is too. httponly=False) # Allow reading this from JS. return response
def updates(self): now = utcnow() current_session = Session.query.filter( Session.start_at <= now, Session.end_at >= now, Session.project == self.obj.venue.project, db.or_(Session.venue_room == self.obj, Session.is_break.is_(True)), ).first() next_session = (Session.query.filter( Session.start_at > now, db.or_(Session.venue_room == self.obj, Session.is_break.is_(True)), Session.project == self.obj.venue.project, ).order_by(Session.start_at).first()) if current_session: current_session.start_at = localize_date( current_session.start_at, to_tz=self.obj.venue.project.timezone) current_session.end_at = localize_date( current_session.end_at, to_tz=self.obj.venue.project.timezone) nextdiff = None if next_session: next_session.start_at = localize_date( next_session.start_at, to_tz=self.obj.venue.project.timezone) next_session.end_at = localize_date( next_session.end_at, to_tz=self.obj.venue.project.timezone) nextdiff = next_session.start_at.date() - now.date() nextdiff = nextdiff.total_seconds() / 86400 return { 'room': self.obj, 'current_session': current_session, 'next_session': next_session, 'nextdiff': nextdiff, }
def is_valid(self): if self.validity == 0: return True # This token is perpetually valid now = utcnow() if self.created_at < now - timedelta(seconds=self.validity): return False return True
def reset_email(user, kwargs): resetreq = PasswordResetRequest.query.filter_by(user=user, reset_code=kwargs['secret']).first() if not resetreq: return render_message(title=_("Invalid reset link"), message=_(u"The reset link you clicked on is invalid")) if resetreq.created_at < utcnow() - timedelta(days=1): # Reset code has expired (> 24 hours). Delete it db.session.delete(resetreq) db.session.commit() return render_message(title=_("Expired reset link"), message=_(u"The reset link you clicked on has expired")) # Logout *after* validating the reset request to prevent DoS attacks on the user logout_internal() db.session.commit() # Reset code is valid. Now ask user to choose a new password form = PasswordResetForm() form.edit_user = user if form.validate_on_submit(): user.password = form.password.data db.session.delete(resetreq) db.session.commit() return render_message(title=_("Password reset complete"), message=Markup( _(u"Your password has been reset. You may now <a href=\"{loginurl}\">login</a> with your new password.").format( loginurl=escape(url_for('.login'))))) return render_form(form=form, title=_("Reset password"), formid='reset', submit=_("Reset password"), message=Markup(_(u"Hello, <strong>{fullname}</strong>. You may now choose a new password.").format( fullname=escape(user.fullname))), ajax=False)
def campaign_view_count_update(campaign_id, user_id=None, anon_user_id=None): if not user_id and not anon_user_id: return if user_id: cv = CampaignView.get_by_ids(campaign_id=campaign_id, user_id=user_id) if not cv: # Could be missing because of begin_nested introduced in 36070d9e without outer commit cv = CampaignView(campaign_id=campaign_id, user_id=user_id) db.session.add(cv) elif anon_user_id: cv = CampaignAnonView.get_by_ids(campaign_id=campaign_id, anon_user_id=anon_user_id) if not cv: # Could be missing because of begin_nested introduced in 36070d9e without outer commit cv = CampaignAnonView(campaign_id=campaign_id, anon_user_id=anon_user_id) db.session.add(cv) query = db.session.query(db.func.count(campaign_event_session_table.c.event_session_id)).filter( campaign_event_session_table.c.campaign_id == campaign_id).join(EventSession).filter( EventSession.active_at >= (cv.reset_at or utcnow())) # FIXME: Run this in a cron job and de-link from post-request processing # query = query.filter( # db.or_( # # Is this event session closed? Criteria: it's been half an hour or the session's explicitly closed # EventSession.ended_at != None, # EventSession.active_at < utcnow() - timedelta(minutes=30))) # NOQA if user_id: query = query.filter(EventSession.user_id == user_id) else: query = query.filter(EventSession.anon_user_id == anon_user_id) cv.session_count = query.first()[0] cv.last_viewed_at = db.func.utcnow() db.session.commit()
def feed( basequery=None, type=None, # NOQA: A002 category=None, md5sum=None, domain=None, location=None, tag=None, title=None, ): title = "All jobs" if type: title = type.title elif category: title = category.title elif md5sum or domain: title = "Jobs at a single employer" elif location: title = "Jobs in {location}".format(location=location['use_title']) elif tag: title = "Jobs tagged {tag}".format(tag=title) posts = list(getposts(basequery, showall=True, limit=100)) if posts: # Can't do this unless posts is a list updated = posts[0].datetime.isoformat() + 'Z' if md5sum: title = posts[0].company_name else: updated = utcnow().isoformat() + 'Z' return Response( render_template('feed-atom.xml', posts=posts, updated=updated, title=title), content_type='application/atom+xml; charset=utf-8', )
def confirm_sale(self): """Update the status to ORDER_STATUS.SALES_ORDER.""" for line_item in self.line_items: line_item.confirm() self.invoice_no = gen_invoice_no(self.organization) self.status = ORDER_STATUS.SALES_ORDER self.paid_at = utcnow()
def new_from_request(cls, request): instance = cls() # We need to set a UUID despite the autogenerated default from UuidMixin, because # EventSessionBase is used independently, isn't a db model, and doesn't have a uuid column. instance.uuid = uuid4() instance.created_at = utcnow() instance.referrer = unicode_http_header(request.referrer)[:2083] if request.referrer else None instance.utm_source = request.args.get('utm_source', u'')[:250] or None instance.utm_medium = request.args.get('utm_medium', u'')[:250] or None instance.utm_term = request.args.get('utm_term', u'')[:250] or None instance.utm_content = request.args.get('utm_content', u'')[:250] or None instance.utm_id = request.args.get('utm_id', u'')[:250] or None instance.utm_campaign = request.args.get('utm_campaign', u'')[:250] or None instance.gclid = request.args.get('gclid', u'')[:250] or None instance.active_at = utcnow() instance.events = [] return instance
def phoneclaims(): """Sweep phone claims to close all unclaimed beyond expiry period (10m)""" pc = models.UserPhoneClaim pc.query.filter( pc.updated_at < (utcnow() - timedelta(hours=1)), pc.verification_expired ).delete() db.session.commit()
def tense(self): now = utcnow() if self.end_at < now: return "past" elif self.start_at > now: return "upcoming" else: return "current"
def is_cancellable(self): tz = current_app.config['tz'] now = localize_timezone(utcnow(), tz) return self.is_confirmed and ( now < localize_timezone(self.item.cancellable_until, tz) if self.item.cancellable_until else True )
def sessions(): """Sweep user sessions to close all inactive sessions (10m)""" es = models.EventSession # Close all sessions that have been inactive for >= 30 minutes es.query.filter(es.ended_at.is_(None), es.active_at < (utcnow() - timedelta(minutes=30))).update( {es.ended_at: es.active_at}) db.session.commit()
def viewstats(self): now = utcnow() delta = now - self.datetime hourly_stat_limit = 2 # days if delta.days < hourly_stat_limit: # Less than {limit} days return 'h', viewstats_by_id_hour(self.id, hourly_stat_limit * 24) else: return 'd', viewstats_by_id_day(self.id, 30)
def _load_user(self): """ If there's a buid in the session, retrieve the user object and add to the request namespace object g. """ add_auth_attribute('user', None) add_auth_attribute('session', None) lastuser_cookie = {} lastuser_cookie_headers = { } # Ignored for now, intended for future changes # Migrate data from Flask cookie session if 'sessionid' in session: lastuser_cookie['sessionid'] = session.pop('sessionid') if 'userid' in session: lastuser_cookie['userid'] = session.pop('userid') if 'lastuser' in request.cookies: try: lastuser_cookie, lastuser_cookie_headers = lastuser_oauth.serializer.loads( request.cookies['lastuser'], return_header=True) except itsdangerous.BadSignature: lastuser_cookie = {} if 'sessionid' in lastuser_cookie: add_auth_attribute( 'session', UserSession.authenticate(buid=lastuser_cookie['sessionid'])) if current_auth.session: current_auth.session.access() db.session.commit() # Save access add_auth_attribute('user', current_auth.session.user) # Transition users with 'userid' to 'sessionid' if not current_auth.session and 'userid' in lastuser_cookie: add_auth_attribute('user', User.get(buid=lastuser_cookie['userid'])) if current_auth.is_authenticated: add_auth_attribute('session', UserSession(user=current_auth.user)) current_auth.session.access() db.session.commit() # Save access if current_auth.session: lastuser_cookie['sessionid'] = current_auth.session.buid else: lastuser_cookie.pop('sessionid', None) if current_auth.is_authenticated: lastuser_cookie['userid'] = current_auth.user.buid else: lastuser_cookie.pop('userid', None) lastuser_cookie['updated_at'] = utcnow().isoformat() add_auth_attribute('cookie', lastuser_cookie) # This will be set to True downstream by the requires_login decorator add_auth_attribute('login_required', False)
def set_loginmethod_cookie(response, value): response.set_cookie( 'login', value, max_age=31557600, # Keep this cookie for a year expires=utcnow() + timedelta(days=365), # Expire one year from now secure=current_app.config['SESSION_COOKIE_SECURE'], httponly=True) return response
def feed_indeed(): title = "All jobs" posts = list(getposts(None, showall=True)) if posts: # Can't do this unless posts is a list updated = posts[0].datetime.isoformat() + 'Z' else: updated = utcnow().isoformat() + 'Z' return Response(render_template('feed-indeed.xml', posts=posts, updated=updated, title=title), content_type='textxml; charset=utf-8')
def sales_delta(user_tz, item_ids): """Calculates the percentage difference in sales between today and yesterday""" today = utcnow().date() yesterday = today - timedelta(days=1) today_sales = sales_by_date(today, item_ids, user_tz) yesterday_sales = sales_by_date(yesterday, item_ids, user_tz) if not today_sales or not yesterday_sales: return 0 return round(Decimal('100') * (today_sales - yesterday_sales) / yesterday_sales, 2)
def delete_expired(cls): """Delete expired phone claims""" # Delete if: # 1. The claim is > 1 hour old # 2. Too many unsuccessful verification attempts cls.query.filter( db.or_( cls.updated_at < (utcnow() - timedelta(hours=1)), cls.verification_expired, )).delete(synchronize_session=False)
def admin_item_collection(item_collection): item_ids = [str(item.id) for item in item_collection.items] date_item_counts = {} date_sales = {} for sales_date, sales_count in counts_per_date_per_item(item_collection, g.user.timezone).items(): date_sales[sales_date.isoformat()] = sales_by_date(sales_date, item_ids, g.user.timezone) date_item_counts[sales_date.isoformat()] = sales_count today_sales = date_sales.get(localize_timezone(utcnow(), g.user.timezone).date().isoformat(), Decimal(0)) return dict(title=item_collection.title, item_collection=item_collection, date_item_counts=date_item_counts, date_sales=date_sales, today_sales=today_sales, sales_delta=sales_delta(g.user.timezone, item_ids))
def sort_score(self): """ Sort with a gravity of 1.8 using the HackerNews algorithm """ viewcounts = self.viewcounts opened = int(viewcounts['opened']) applied = int(viewcounts['applied']) age = utcnow() - self.datetime hours = age.days * 24 + age.seconds // 3600 return ((applied * 3) + (opened - applied)) / pow((hours + 2), 1.8)
def test_user_password_has_expired(self): """ Test to check if password for a user has expired """ alexis = models.User(username='******', fullname='Alexis Castle') alexis.password = '******' alexis.pw_expires_at = utcnow() + timedelta(0, 0, 1) db.session.add(alexis) db.session.commit() result = models.User.get(buid=alexis.buid) self.assertIsNotNone(result) self.assertTrue(alexis.password_has_expired())
def test_utcnow(self): """Test that Coaster's utcnow works correctly""" # Get date from function being tested now1 = utcnow() # Get date from Python stdlib now2 = datetime.datetime.utcnow() # 1. Our function returns a date that has a timezone assert now1.tzinfo is not None # 2. The timezone is UTC because its offset is zero assert now1.tzinfo.utcoffset(now1) == datetime.timedelta(0) # 3. And it's within a second of the comparison date (the runtime environment # cannot possibly have taken over a second between two consecutive statements) assert abs(now2 - now1.replace(tzinfo=None)) < datetime.timedelta(seconds=1)