From 12fdd7042f6e2af4c21182609631d76afd42d437 Mon Sep 17 00:00:00 2001
From: Bibhas
Date: Wed, 4 Apr 2018 01:40:10 +0530
Subject: [PATCH 01/14] Moving anon user tracking from image element to form
submit
---
hasjob/templates/formlayout.html.jinja2 | 2 +
hasjob/templates/layout.html.jinja2 | 8 +-
hasjob/templates/macros.html.jinja2 | 34 ++++++
hasjob/templates/sheet.html.jinja2 | 3 +-
hasjob/templates/tablayout.html.jinja2 | 2 +
hasjob/views/helper.py | 139 +++++++++++-------------
hasjob/views/index.py | 1 -
7 files changed, 107 insertions(+), 82 deletions(-)
diff --git a/hasjob/templates/formlayout.html.jinja2 b/hasjob/templates/formlayout.html.jinja2
index a81c7c9a7..dee9b718a 100644
--- a/hasjob/templates/formlayout.html.jinja2
+++ b/hasjob/templates/formlayout.html.jinja2
@@ -1,3 +1,4 @@
+{% from "macros.html.jinja2" import anon_user_script %}
{%- if current_view.tabs -%}
{%- extends "tablayout.html.jinja2" -%}
{%- else -%}
@@ -27,4 +28,5 @@
{%- if header_campaign %}{{ campaign_script() }}{% endif %}
{% assets "js_tinymce" %}{% endassets %}
{% block footerscripts %}{% endblock %}
+ {{ anon_user_script() }}
{% endblock %}
diff --git a/hasjob/templates/layout.html.jinja2 b/hasjob/templates/layout.html.jinja2
index 68c3b45da..ef338e4d3 100644
--- a/hasjob/templates/layout.html.jinja2
+++ b/hasjob/templates/layout.html.jinja2
@@ -1,6 +1,6 @@
{%- extends "baseframe.html.jinja2" -%}
{%- from "baseframe/components.html.jinja2" import hgnav -%}
-{%- from "macros.html.jinja2" import campaign_header, campaign_script, filters_setup_script -%}
+{%- from "macros.html.jinja2" import campaign_header, campaign_script, filters_setup_script, anon_user_script -%}
{%- block doctypehtml -%}
@@ -54,7 +54,7 @@
{{ filters_setup_script(job_filters, data_filters) }}
{%- else %}
{{ filters_setup_script(job_filters) }}
- {%- endif %}
+ {%- endif %}
{%- endif %}
{%- endblock %}
@@ -225,13 +225,11 @@
to find out when new jobs are posted. Hosted by
E2E Networks.
{%- endif %}
- {%- if not g.user and not g.anon_user %}
-
- {%- endif %}
{% endblock %}
{% block layoutscripts %}
{%- if header_campaign %}{{ campaign_script() }}{% endif %}
{% block footerscripts %}{% endblock %}
+ {{ anon_user_script() }}
{% endblock %}
diff --git a/hasjob/templates/macros.html.jinja2 b/hasjob/templates/macros.html.jinja2
index 65ad2e12e..c47d4d0ff 100644
--- a/hasjob/templates/macros.html.jinja2
+++ b/hasjob/templates/macros.html.jinja2
@@ -207,3 +207,37 @@
{%- endwith %}
{%- endmacro -%}
+
+{%- macro anon_user_script() -%}
+ {%- if not g.user and not g.anon_user %}
+
+ {%- endif %}
+{%- endmacro -%}
+
diff --git a/hasjob/templates/sheet.html.jinja2 b/hasjob/templates/sheet.html.jinja2
index 95f023cd1..4a52ec016 100644
--- a/hasjob/templates/sheet.html.jinja2
+++ b/hasjob/templates/sheet.html.jinja2
@@ -1,5 +1,5 @@
{%- extends "layout.html.jinja2" -%}
-{%- from "macros.html.jinja2" import campaign_header, campaign_script -%}
+{%- from "macros.html.jinja2" import campaign_header, campaign_script, anon_user_script -%}
{% block messages %}{% endblock %}
{% block basecontent %}
{%- if header_campaign %}{% endif %}
@@ -24,4 +24,5 @@
{% block layoutscripts %}
{%- if header_campaign %}{{ campaign_script() }}{% endif %}
{% block footerscripts %}{% endblock %}
+ {{ anon_user_script() }}
{% endblock %}
diff --git a/hasjob/templates/tablayout.html.jinja2 b/hasjob/templates/tablayout.html.jinja2
index 6f669d089..332ba08c2 100644
--- a/hasjob/templates/tablayout.html.jinja2
+++ b/hasjob/templates/tablayout.html.jinja2
@@ -1,3 +1,4 @@
+{% from "macros.html.jinja2" import anon_user_script %}
{%- extends "layout.html.jinja2" -%}
{% block pageheaders %}
@@ -31,4 +32,5 @@
{% block footerscripts %}{% endblock %}
+ {{ anon_user_script() }}
{% endblock %}
diff --git a/hasjob/views/helper.py b/hasjob/views/helper.py
index ff9802ee7..f37f71710 100644
--- a/hasjob/views/helper.py
+++ b/hasjob/views/helper.py
@@ -10,7 +10,7 @@
from sqlalchemy import or_
from sqlalchemy.exc import IntegrityError
from geoip2.errors import AddressNotFoundError
-from flask import Markup, request, g, session
+from flask import Markup, request, g, session, Response
from flask_rq import job
from flask_lastuser import signal_user_looked_up
from coaster.sqlalchemy import failsafe_add
@@ -28,14 +28,55 @@
gif1x1 = 'R0lGODlhAQABAJAAAP8AAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw=='.decode('base64')
-@app.route('/_sniffle.gif')
+@app.route('/_sniffle', methods=['POST'])
def sniffle():
- return gif1x1, 200, {
- 'Content-Type': 'image/gif',
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
- 'Pragma': 'no-cache',
- 'Expires': '0'
- }
+ """
+ Load anon user:
+
+ 1. If there's g.user and session['anon_user'], it loads that anon_user and tags with user=g.user, then removes anon
+ 2. If there's no g.user and no session['anon_user'] and form submitted token matches session['au'], sets session['anon_user'] = 'test'
+ 3. If there's no g.user and there is session['au'] != form['token'], loads g.anon_user
+ """
+ # Loading an anon user only if we're not rendering static resources
+ if g.user:
+ if 'au' in session and session['au'] is not None and not unicode(session['au']).startswith(u'test'):
+ anon_user = AnonUser.query.get(session['au'])
+ if anon_user:
+ anon_user.user = g.user
+ session.pop('au', None)
+ else:
+ if unicode(session['au']).startswith('test') and unicode(session['au']) == request.form.get('token'):
+ # This client sent us back our test cookie, so set a real value now
+ g.anon_user = AnonUser()
+ db.session.add(g.anon_user)
+ g.esession = EventSession.new_from_request(request)
+ g.esession.anon_user = g.anon_user
+ db.session.add(g.esession)
+ g.esession.load_from_cache(session['au'], UserEvent)
+ # We'll update session['au'] below after database commit
+ else:
+ anon_user = AnonUser.query.get(session['au'])
+ if not anon_user:
+ # XXX: We got a fake value? This shouldn't happen
+ g.event_data['anon_cookie_test'] = session['au']
+ session['au'] = u'test-' + unicode(uuid4()) # Try again
+ g.esession = EventSessionBase.new_from_request(request)
+ else:
+ g.anon_user = anon_user
+
+ db.session.commit()
+
+ if g.anon_user:
+ session['au'] = g.anon_user.id
+ session.permanent = True
+
+ # Prepare event session if it's not already present
+ if g.user or g.anon_user and not g.esession:
+ g.esession = EventSession.get_session(uuid=session.get('es'), user=g.user, anon_user=g.anon_user)
+ if g.esession:
+ session['es'] = g.esession.uuid
+
+ return Response("OK")
def index_is_paginated():
@@ -66,18 +107,11 @@ def load_user_data(user):
"""
All pre-request utilities, run after g.user becomes available.
- Part 1: Load anon user:
-
- 1. If there's g.user and session['anon_user'], it loads that anon_user and tags with user=g.user, then removes anon
- 2. If there's no g.user and no session['anon_user'], sets session['anon_user'] = 'test'
- 3. If there's no g.user and there is session['anon_user'] = 'test', creates a new anon user, then saves to cookie
- 4. If there's no g.user and there is session['anon_user'] != 'test', loads g.anon_user
-
Part 2: Are we in kiosk mode? Is there a preview campaign?
Part 3: Look up user's IP address location as geonameids for use in targeting.
"""
- g.anon_user = None # Could change below
- g.event_data = {} # Views can add data to the current pageview event
+ g.anon_user = None
+ g.event_data = {}
g.esession = None
g.viewcounts = {}
g.impressions = session.pop('impressions', {}) # Retrieve from cookie session if present there
@@ -86,66 +120,21 @@ def load_user_data(user):
g.bgroup = None
now = datetime.utcnow()
- if request.endpoint not in ('static', 'baseframe.static'):
- # Loading an anon user only if we're not rendering static resources
- if user:
- if 'au' in session and session['au'] is not None and not unicode(session['au']).startswith(u'test'):
- anon_user = AnonUser.query.get(session['au'])
- if anon_user:
- anon_user.user = user
- session.pop('au', None)
- else:
- if not session.get('au'):
- session['au'] = u'test-' + unicode(uuid4())
- g.esession = EventSessionBase.new_from_request(request)
- g.event_data['anon_cookie_test'] = session['au']
- # elif session['au'] == 'test': # Legacy test cookie, original request now lost
- # g.anon_user = AnonUser()
- # db.session.add(g.anon_user)
- # g.esession = EventSession.new_from_request(request)
- # g.esession.anon_user = g.anon_user
- # db.session.add(g.esession)
- # # We'll update session['au'] below after database commit
- # elif unicode(session['au']).startswith('test-'): # Newer redis-backed test cookie
- # # This client sent us back our test cookie, so set a real value now
- # g.anon_user = AnonUser()
- # db.session.add(g.anon_user)
- # g.esession = EventSession.new_from_request(request)
- # g.esession.anon_user = g.anon_user
- # db.session.add(g.esession)
- # g.esession.load_from_cache(session['au'], UserEvent)
- # # We'll update session['au'] below after database commit
- else:
- anon_user = None # AnonUser.query.get(session['au'])
- if not anon_user:
- # XXX: We got a fake value? This shouldn't happen
- g.event_data['anon_cookie_test'] = session['au']
- session['au'] = u'test-' + unicode(uuid4()) # Try again
- g.esession = EventSessionBase.new_from_request(request)
- else:
- g.anon_user = anon_user
+ if 'au' not in session or session['au'] is None:
+ session['au'] = u'test-' + unicode(uuid4())
+ g.esession = EventSessionBase.new_from_request(request)
+ g.event_data['anon_cookie_test'] = session['au']
+ elif not unicode(session['au']).startswith(u'test'):
+ anon_user = AnonUser.query.get(session['au'])
+ if anon_user:
+ g.anon_user = anon_user
- # Prepare event session if it's not already present
- if g.user or g.anon_user and not g.esession:
- g.esession = EventSession.get_session(uuid=session.get('es'), user=g.user, anon_user=g.anon_user)
- if g.esession:
- session['es'] = g.esession.uuid
-
- # Don't commit here. It flushes SQLAlchemy's session cache and forces
- # fresh database hits. Let after_request commit. (Commented out 30-03-2016)
- # db.session.commit()
- g.db_commit_needed = True
-
- if g.anon_user:
- session['au'] = g.anon_user.id
- session.permanent = True
- if 'impressions' in session:
- # Run this in the foreground since we need this later in the request for A/B display consistency.
- # This is most likely being called from the UI-non-blocking sniffle.gif anyway.
- save_impressions(g.esession.id, session.pop('impressions').values(), now)
+ if g.anon_user and 'impressions' in session:
+ # Run this in the foreground since we need this later in the request for A/B display consistency.
+ # This is most likely being called from the UI-non-blocking sniffle.gif anyway.
+ save_impressions(g.esession.id, session.pop('impressions').values(), now)
# We have a user, now look up everything else
-
if session.get('kiosk'):
g.kiosk = True
else:
@@ -313,7 +302,7 @@ def session_jobpost_ab():
Returns the user's B-group assignment (NA, True, False) for all jobs shown to the user
in the current event session (impressions or views) as a dictionary of {id: bgroup}
"""
- if not g.esession.persistent:
+ if g.esession and not g.esession.persistent:
return {key: value[2] for key, value in session.get('impressions', {}).items()}
result = {ji.jobpost_id: ji.bgroup for ji in JobImpression.query.filter_by(event_session=g.esession)}
result.update({jvs.jobpost_id: jvs.bgroup for jvs in JobViewSession.query.filter_by(event_session=g.esession)})
diff --git a/hasjob/views/index.py b/hasjob/views/index.py
index 892f4cd10..239d65a93 100644
--- a/hasjob/views/index.py
+++ b/hasjob/views/index.py
@@ -353,7 +353,6 @@ def index(basequery=None, filters={}, md5sum=None, tag=None, domain=None, locati
BoardJobPost.board == g.board, JobPost.state.LISTED).options(
db.load_only('jobpost_id', 'pinned')).all()
}
-
else:
board_jobs = {}
From 6dd80bea5ce921fa91fd2ce8388ed0efccfd9cd1 Mon Sep 17 00:00:00 2001
From: Bibhas
Date: Thu, 5 Apr 2018 01:58:35 +0530
Subject: [PATCH 02/14] fixes in handling anon user and associating with actual
user upon login
---
hasjob/views/helper.py | 43 ++++++++++++++++++++----------------------
1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/hasjob/views/helper.py b/hasjob/views/helper.py
index f37f71710..d068a268e 100644
--- a/hasjob/views/helper.py
+++ b/hasjob/views/helper.py
@@ -37,14 +37,7 @@ def sniffle():
2. If there's no g.user and no session['anon_user'] and form submitted token matches session['au'], sets session['anon_user'] = 'test'
3. If there's no g.user and there is session['au'] != form['token'], loads g.anon_user
"""
- # Loading an anon user only if we're not rendering static resources
- if g.user:
- if 'au' in session and session['au'] is not None and not unicode(session['au']).startswith(u'test'):
- anon_user = AnonUser.query.get(session['au'])
- if anon_user:
- anon_user.user = g.user
- session.pop('au', None)
- else:
+ if not g.user:
if unicode(session['au']).startswith('test') and unicode(session['au']) == request.form.get('token'):
# This client sent us back our test cookie, so set a real value now
g.anon_user = AnonUser()
@@ -55,16 +48,12 @@ def sniffle():
g.esession.load_from_cache(session['au'], UserEvent)
# We'll update session['au'] below after database commit
else:
- anon_user = AnonUser.query.get(session['au'])
- if not anon_user:
- # XXX: We got a fake value? This shouldn't happen
- g.event_data['anon_cookie_test'] = session['au']
- session['au'] = u'test-' + unicode(uuid4()) # Try again
- g.esession = EventSessionBase.new_from_request(request)
- else:
- g.anon_user = anon_user
-
- db.session.commit()
+ # form submitted token doesn't match the already set session['au']
+ # XXX: We got a fake value? This shouldn't happen
+ g.event_data['anon_cookie_test'] = session['au']
+ session['au'] = u'test-' + unicode(uuid4()) # Try again
+ g.esession = EventSessionBase.new_from_request(request)
+ db.session.commit()
if g.anon_user:
session['au'] = g.anon_user.id
@@ -120,14 +109,22 @@ def load_user_data(user):
g.bgroup = None
now = datetime.utcnow()
- if 'au' not in session or session['au'] is None:
+ if 'au' in session and session['au'] is not None:
+ if not unicode(session['au']).startswith(u'test'):
+ # fetch anon user and set anon_user.user
+ anon_user = AnonUser.query.get(session['au'])
+ if anon_user and g.user:
+ # we have anon user id in session['au'], set anon_user.user to current user
+ anon_user.user = g.user
+ g.db_commit_needed = True
+ session.pop('au', None)
+ elif anon_user and not g.user:
+ # set g.anon_user
+ g.anon_user = anon_user
+ elif not g.user:
session['au'] = u'test-' + unicode(uuid4())
g.esession = EventSessionBase.new_from_request(request)
g.event_data['anon_cookie_test'] = session['au']
- elif not unicode(session['au']).startswith(u'test'):
- anon_user = AnonUser.query.get(session['au'])
- if anon_user:
- g.anon_user = anon_user
if g.anon_user and 'impressions' in session:
# Run this in the foreground since we need this later in the request for A/B display consistency.
From 8648385e2a983d8734431c1ae1451a4b3b7f00d4 Mon Sep 17 00:00:00 2001
From: Bibhas
Date: Thu, 5 Apr 2018 02:04:59 +0530
Subject: [PATCH 03/14] added comment
---
hasjob/views/helper.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/hasjob/views/helper.py b/hasjob/views/helper.py
index d068a268e..21fa03e5d 100644
--- a/hasjob/views/helper.py
+++ b/hasjob/views/helper.py
@@ -96,6 +96,8 @@ def load_user_data(user):
"""
All pre-request utilities, run after g.user becomes available.
+ Part 1: If session['au'] exists, either set g.anon_user or set anon_user.user (if g.user exists).
+ If session['au'] does not exist, set it
Part 2: Are we in kiosk mode? Is there a preview campaign?
Part 3: Look up user's IP address location as geonameids for use in targeting.
"""
From 72139e28af27bd9ac6b7cbc0dd25f336b0e9f5ec Mon Sep 17 00:00:00 2001
From: Bibhas
Date: Thu, 5 Apr 2018 14:04:47 +0530
Subject: [PATCH 04/14] moved eventsession setting to per request
---
hasjob/views/helper.py | 55 +++++++++++++++++++++---------------------
1 file changed, 28 insertions(+), 27 deletions(-)
diff --git a/hasjob/views/helper.py b/hasjob/views/helper.py
index 21fa03e5d..daf1d0703 100644
--- a/hasjob/views/helper.py
+++ b/hasjob/views/helper.py
@@ -59,12 +59,6 @@ def sniffle():
session['au'] = g.anon_user.id
session.permanent = True
- # Prepare event session if it's not already present
- if g.user or g.anon_user and not g.esession:
- g.esession = EventSession.get_session(uuid=session.get('es'), user=g.user, anon_user=g.anon_user)
- if g.esession:
- session['es'] = g.esession.uuid
-
return Response("OK")
@@ -111,27 +105,34 @@ def load_user_data(user):
g.bgroup = None
now = datetime.utcnow()
- if 'au' in session and session['au'] is not None:
- if not unicode(session['au']).startswith(u'test'):
- # fetch anon user and set anon_user.user
- anon_user = AnonUser.query.get(session['au'])
- if anon_user and g.user:
- # we have anon user id in session['au'], set anon_user.user to current user
- anon_user.user = g.user
- g.db_commit_needed = True
- session.pop('au', None)
- elif anon_user and not g.user:
- # set g.anon_user
- g.anon_user = anon_user
- elif not g.user:
- session['au'] = u'test-' + unicode(uuid4())
- g.esession = EventSessionBase.new_from_request(request)
- g.event_data['anon_cookie_test'] = session['au']
-
- if g.anon_user and 'impressions' in session:
- # Run this in the foreground since we need this later in the request for A/B display consistency.
- # This is most likely being called from the UI-non-blocking sniffle.gif anyway.
- save_impressions(g.esession.id, session.pop('impressions').values(), now)
+ if request.endpoint not in ('static', 'baseframe.static'):
+ if 'au' in session and session['au'] is not None:
+ if not unicode(session['au']).startswith(u'test'):
+ # fetch anon user and set anon_user.user
+ anon_user = AnonUser.query.get(session['au'])
+ if anon_user and g.user:
+ # we have anon user id in session['au'], set anon_user.user to current user
+ anon_user.user = g.user
+ g.db_commit_needed = True
+ session.pop('au', None)
+ elif anon_user and not g.user:
+ # set g.anon_user
+ g.anon_user = anon_user
+ elif not g.user:
+ session['au'] = u'test-' + unicode(uuid4())
+ g.esession = EventSessionBase.new_from_request(request)
+ g.event_data['anon_cookie_test'] = session['au']
+
+ # Prepare event session if it's not already present
+ if g.user or g.anon_user and not g.esession:
+ g.esession = EventSession.get_session(uuid=session.get('es'), user=g.user, anon_user=g.anon_user)
+ if g.esession:
+ session['es'] = g.esession.uuid
+
+ if g.anon_user and 'impressions' in session:
+ # Run this in the foreground since we need this later in the request for A/B display consistency.
+ # This is most likely being called from the UI-non-blocking sniffle.gif anyway.
+ save_impressions(g.esession.id, session.pop('impressions').values(), now)
# We have a user, now look up everything else
if session.get('kiosk'):
From 426e753451ff230aae5df1e0f936b68a2c636b2a Mon Sep 17 00:00:00 2001
From: Bibhas
Date: Fri, 6 Apr 2018 01:46:51 +0530
Subject: [PATCH 05/14] renamed sniffle and moved to api views
---
hasjob/templates/macros.html.jinja2 | 24 +++++-----
hasjob/views/api.py | 37 +++++++++++++--
hasjob/views/helper.py | 71 ++++++++---------------------
3 files changed, 64 insertions(+), 68 deletions(-)
diff --git a/hasjob/templates/macros.html.jinja2 b/hasjob/templates/macros.html.jinja2
index c47d4d0ff..9c284d4a0 100644
--- a/hasjob/templates/macros.html.jinja2
+++ b/hasjob/templates/macros.html.jinja2
@@ -212,28 +212,28 @@
{%- if not g.user and not g.anon_user %}