diff --git a/hasjob/models/jobpost.py b/hasjob/models/jobpost.py
index 07737de0f..e0e430b59 100644
--- a/hasjob/models/jobpost.py
+++ b/hasjob/models/jobpost.py
@@ -10,7 +10,6 @@
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.dialects.postgresql import TSVECTOR
import tldextract
-from coaster.auth import current_auth
from coaster.sqlalchemy import make_timestamp_columns, Query, JsonDict, StateManager
from baseframe import cache, _, __
from baseframe.utils import is_public_email_domain
@@ -426,7 +425,7 @@ def tag_content(self):
Markup('
') + Markup(escape(self.headline)) + Markup('
'),
Markup('') + Markup(self.description) + Markup('
'),
Markup('') + Markup(self.perks) + Markup('
')
- ))
+ ))
@staticmethod
def viewcounts_key(jobpost_id):
diff --git a/hasjob/static/css/app.css b/hasjob/static/css/app.css
index 91d65f572..a54688f54 100644
--- a/hasjob/static/css/app.css
+++ b/hasjob/static/css/app.css
@@ -933,9 +933,8 @@ tr > div {
position: relative;
vertical-align: top;
display: block;
- font-family: "McLaren", sans-serif;
overflow: visible;
- padding: 24px 18px;
+ padding: 24px 0 0;
word-wrap: break-word;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -956,17 +955,11 @@ tr > div {
.stickie label {
font-weight: normal;
}
-.stickie .count {
- font-size: 90%;
- color: #816894;
- display: block;
-}
.stickie .annotation {
font-size: 75%;
display: block;
position: absolute;
color: #816894;
- font-family: "McLaren", sans-serif;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
@@ -981,19 +974,127 @@ tr > div {
left: 0.5em;
width: 75%;
}
-.stickie .bottom-right {
- right: 0.5em;
- bottom: 0.1em;
- width: 70%;
- text-align: right;
+.stickie .headline,
+.stickie .pay {
+ display: block;
+ padding: 0 18px;
+ position: static;
}
-.stickie .bottom-left {
- left: 0.5em;
- bottom: 0.1em;
+.stickie .headline {
+ font-family: "McLaren", sans-serif;
+}
+.stickie .star {
+ position: static;
+ float: left;
+ width: 20%;
+ margin-left: 0.5em;
}
.stickie .new {
color: #df5e0e;
}
+.stickie .company-name {
+ position: static;
+ float: right;
+ width: 70%;
+ text-align: right;
+ margin-right: 0.5em;
+}
+.stickie .count {
+ margin-top: 5px;
+ color: #816894;
+ display: flex;
+}
+.stickie .count-items {
+ flex: 1;
+ font-size: 9px;
+}
+.stickie .count-text {
+ display: inline-block;
+ width: calc(100% - 6px);
+}
+.stickie .count-items.impressions {
+ flex: 1.5;
+}
+.stickie .count-arrow {
+ float: right;
+}
+.stickie .count-text,
+.stickie .count-arrow {
+ font-size: 10px;
+}
+@media (min-width: 480px) {
+ .stickie .count-text,
+ .stickie .count-arrow {
+ font-size: 14px;
+ }
+}
+@media (min-width: 768px) {
+ .stickie .count-text,
+ .stickie .count-arrow {
+ font-size: 7px;
+ }
+ .stickie .count-arrow {
+ margin-top: 2px;
+ }
+}
+@media (min-width: 1200px) {
+ .stickie .count-text,
+ .stickie .count-arrow {
+ font-size: 8px;
+ }
+ .stickie .count-arrow {
+ margin-top: 1px;
+ }
+}
+.stickie .count-background {
+ display: flex;
+ height: 7px;
+ margin-top: 4px;
+ border-radius: 0 0 2px 2px;
+ overflow: hidden;
+ padding: 0;
+ list-style: none;
+}
+.stickie .count-background .background {
+ flex: 1;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+.stickie .count-background .impressions.background {
+ flex: 1.5;
+ position: relative;
+ z-index: 4;
+}
+.stickie .count-background .viewed.background {
+ position: relative;
+ z-index: 3;
+}
+.stickie .count-background .opened.background {
+ position: relative;
+ z-index: 2;
+}
+.stickie .count-background .applied.background {
+ position: relative;
+ z-index: 1;
+}
+.stickie .count-background .background.arrow:before {
+ content: "";
+ display: inline-block;
+ width: 7px;
+ height: 7px;
+ border-style: solid;
+ border-width: 2px 2px 0 0;
+ border-color: #ffffa2;
+ position: absolute;
+ top: 0;
+ right: -2px;
+ vertical-align: top;
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ -webkit-transform: rotate(45deg);
+ transform: rotate(45deg);
+}
.stickie .pinned {
text-indent: -10000px;
display: block;
@@ -1047,6 +1148,11 @@ tr > div {
left: 1.5em;
right: 1.5em;
}
+.stickie.grouped.under .count-background {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+}
.no-touch li:hover > .stickie.grouped.under {
top: 0px;
left: 15px;
@@ -1103,6 +1209,7 @@ tr > div {
.stickie.special {
background-color: #f6f6f6;
+ padding: 24px 18px;
}
.stickie.org {
@@ -1283,6 +1390,7 @@ tr > div {
text-align: center;
width: auto;
margin: 24px 0;
+ padding: 24px 18px;
}
#i40x {
diff --git a/hasjob/static/js/app.js b/hasjob/static/js/app.js
index ac5238a66..9bd33c50e 100644
--- a/hasjob/static/js/app.js
+++ b/hasjob/static/js/app.js
@@ -1,7 +1,7 @@
//window.Hasjob initialized in layout.html
Hasjob.Util = {
- updateGA: function(){
+ updateGA: function() {
/*
Resets the path in the tracker object and updates GA with the current path.
To be called after updating the URL with pushState or replaceState.
@@ -12,6 +12,17 @@ Hasjob.Util = {
window.ga('set', 'page', path);
window.ga('send', 'pageview');
}
+ },
+ createCustomEvent: function(eventName) {
+ // Raise a custom event
+ if (typeof(window.Event) === "function") {
+ var customEvent = new Event(eventName);
+ } else {
+ // 'Event' constructor is not supported by IE
+ var customEvent = document.createEvent('Event');
+ customEvent.initEvent(eventName, true, true);
+ }
+ return customEvent;
}
};
@@ -73,7 +84,7 @@ window.Hasjob.JobPost = {
window.Hasjob.StickieList = {
init: function(){
- var stickielist = this;
+ window.dispatchEvent(Hasjob.Util.createCustomEvent('onStickiesInit'));
},
loadmore: function(config){
var stickielist = this;
@@ -94,6 +105,7 @@ window.Hasjob.StickieList = {
$('ul#stickie-area').append(data.trim());
stickielist.loadmoreRactive.set('loading', false);
stickielist.loadmoreRactive.set('error', false);
+ window.dispatchEvent(Hasjob.Util.createCustomEvent('onStickiesPagination'));
},
error: function() {
stickielist.loadmoreRactive.set('error', true);
@@ -153,11 +165,97 @@ window.Hasjob.StickieList = {
$('#main-content').html(data);
window.Hasjob.Filters.refresh();
NProgress.done();
+ window.dispatchEvent(Hasjob.Util.createCustomEvent('onStickiesRefresh'));
}
});
history.replaceState({reloadOnPop: true}, '', window.location.href);
history.pushState({reloadOnPop: true}, '', searchUrl);
window.Hasjob.Util.updateGA();
+ },
+ createGradientColourScale: function(funnelName, maxValue) {
+ /*
+ Creates a linear colour gradient with canvas of width equal to maxValue. The canvas indicates a scale from 0 to maxValue.
+
+ Takes
+ 'funnelName' - conversion funnel's name.
+ 'maxValue' - max value of conversion funnel across job posts of last 30 days
+ */
+
+ var canvas = document.createElement("canvas");
+ canvas.id = funnelName;
+ canvas.width = maxValue;
+ canvas.height = 10;
+
+ var context = canvas.getContext('2d');
+ context.rect(0, 0, canvas.width, canvas.height);
+ var grd = context.createLinearGradient(0, 0, canvas.width, canvas.height);
+
+ grd.addColorStop(1, '#DF3499');
+ grd.addColorStop(0.7, '#E05F26');
+ grd.addColorStop(0.5, '#DF5C2A');
+ grd.addColorStop(0.1, '#F1D564');
+ grd.addColorStop(0, '#FFFFA2');
+
+ context.fillStyle = grd;
+ context.fill();
+ //Store the canvas context and end colour of the conversion funnel, later to be used by window.Hasjob.Util.setFunnelColour for picking the colour for a conversion funnel value for a job post.
+ window.Hasjob.Config[funnelName] = {};
+ window.Hasjob.Config[funnelName].canvasContext = context;
+ window.Hasjob.Config[funnelName].maxColour = '#DF3499';
+ },
+ setGradientColour: function(funnelName, value, elementId) {
+ /*
+ Picks the colour for the value from the colour gradient canvas based on a scale of 0 to maxValue.
+
+ Takes 'funnelName', value, elementId'
+ 'funnelName' - conversion funnel's name.
+ 'value' - conversion funnel value for the job post
+ 'elementId' - id attribute of the element of which background colour is to be set
+ */
+
+ //rgba - RGBA values at a particular point in the canvas.
+ var rgba = window.Hasjob.Config[funnelName].canvasContext.getImageData(value, 1, 1, 1).data;
+ if (rgba[0] > 255 || rgba[1] > 255 || rgba[2] > 255) {
+ // rgb value is invalid, hence return white
+ colourHex ="#FFFFFF";
+ } else if (rgba[0] == 0 && rgba[1] == 0 && rgba[2] == 0) {
+ // value greater than maxValue hence return the last colour of the gradient
+ colourHex = window.Hasjob.Config[funnelName].maxColour;
+ } else {
+ // Get the colour code in hex from RGB values returned by getImageData
+ colourHex = "#" + (("000000" + (rgba[0] << 16) | (rgba[1] << 8) | rgba[2]).toString(16)).slice(-6);
+ }
+ // Set the background colour of the element
+ var element = document.getElementById(elementId);
+ element.classList.add("funnel-color-set");
+ element.style.backgroundColor = colourHex;
+ },
+ renderGradientColour: function() {
+ $('.js-funnel').each(function() {
+ if(!$(this).hasClass("funnel-color-set")) {
+ Hasjob.StickieList.setGradientColour($(this).data('funnel-name'), $(this).data('funnel-value'), $(this).attr('id'));
+ }
+ });
+ },
+ createGradientColour: function() {
+ Hasjob.StickieList.createGradientColourScale('impressions', Hasjob.Config.MaxCounts.max_impressions);
+ Hasjob.StickieList.createGradientColourScale('views', Hasjob.Config.MaxCounts.max_views);
+ Hasjob.StickieList.createGradientColourScale('opens', Hasjob.Config.MaxCounts.max_opens);
+ Hasjob.StickieList.createGradientColourScale('applied', Hasjob.Config.MaxCounts.max_applied);
+ },
+ initFunnelViz: function() {
+ window.addEventListener('onStickiesInit', function (e) {
+ Hasjob.StickieList.createGradientColour();
+ Hasjob.StickieList.renderGradientColour();
+ }, false);
+
+ window.addEventListener('onStickiesRefresh', function (e) {
+ Hasjob.StickieList.renderGradientColour();
+ }, false);
+
+ window.addEventListener('onStickiesPagination', function (e) {
+ Hasjob.StickieList.renderGradientColour();
+ }, false);
}
};
@@ -589,6 +687,9 @@ $(function() {
window.Hasjob.Filters.init();
window.Hasjob.JobPost.handleStarClick();
window.Hasjob.JobPost.handleGroupClick();
+ if (window.Hasjob.Config.MaxCounts) {
+ window.Hasjob.StickieList.initFunnelViz();
+ }
var getCurrencyVal = function() {
return $("input[type='radio'][name='currency']:checked").val();
diff --git a/hasjob/static/sass/_40x.scss b/hasjob/static/sass/_40x.scss
index 3ff162969..392eab270 100644
--- a/hasjob/static/sass/_40x.scss
+++ b/hasjob/static/sass/_40x.scss
@@ -8,6 +8,7 @@
text-align: center;
width: auto;
margin: 24px 0;
+ padding: 24px 18px;
}
#i40x {
font-size: 150px;
diff --git a/hasjob/static/sass/_stickie.sass b/hasjob/static/sass/_stickie.sass
index e64837b95..9e2459e0a 100644
--- a/hasjob/static/sass/_stickie.sass
+++ b/hasjob/static/sass/_stickie.sass
@@ -15,9 +15,8 @@
position: relative
vertical-align: top
display: block
- font-family: $font-stickie-headline
overflow: visible // To make shadow visible
- padding: 24px 18px
+ padding: 24px 0 0
word-wrap: break-word
+box-sizing(border-box)
+border-radius(2px)
@@ -32,44 +31,140 @@
label
font-weight: normal
- .count
- font-size: 90%
- color: $color-stickie-location
- display: block
-
.annotation
font-size: 75%
display: block
position: absolute
color: $color-stickie-location
- font-family: $font-stickie-headline
overflow: hidden
white-space: nowrap
text-overflow: ellipsis
height: 1.5em
.top-right
- top: 0.1em
- right: 0.5em
+ top: .1em
+ right: .5em
.top-left
- top: 0.1em
- left: 0.5em
+ top: .1em
+ left: .5em
width: 75%
- .bottom-right
- right: 0.5em
- bottom: 0.1em
- width: 70%
- text-align: right
+ .headline,
+ .pay,
+ display: block
+ padding: 0 18px
+ position: static
- .bottom-left
- left: 0.5em
- bottom: 0.1em
+ .headline
+ font-family: $font-stickie-headline
+
+ .star
+ position: static
+ float: left
+ width: 20%
+ margin-left: 0.5em
.new
color: $color-stickie-new
+ .company-name
+ position: static
+ float: right
+ width: 70%
+ text-align: right
+ margin-right: 0.5em
+
+ .count
+ margin-top: 5px
+ color: $color-stickie-location
+ display: flex
+
+ .count-items
+ flex: 1
+ font-size: 9px
+
+ .count-text
+ display: inline-block
+ width: calc(100% - 6px)
+
+ .count-items.impressions
+ flex: 1.5
+
+ .count-arrow
+ float: right
+
+ .count-text,
+ .count-arrow
+ font-size: 10px
+
+ @media (min-width: 480px)
+ .count-text,
+ .count-arrow
+ font-size: 14px
+
+ @media (min-width: 768px)
+ .count-text,
+ .count-arrow
+ font-size: 7px
+
+ .count-arrow
+ margin-top: 2px
+
+ @media (min-width: 1200px)
+ .count-text,
+ .count-arrow
+ font-size: 8px
+
+ .count-arrow
+ margin-top: 1px
+
+ .count-background
+ display: flex
+ height: 7px
+ margin-top: 4px
+ border-radius: 0 0 2px 2px
+ overflow: hidden
+ padding: 0
+ list-style: none
+
+ .background
+ flex: 1
+ height: 100%
+ margin: 0
+ padding: 0
+
+ .impressions.background
+ flex: 1.5
+ position: relative
+ z-index: 4
+
+ .viewed.background
+ position: relative
+ z-index: 3
+
+ .opened.background
+ position: relative
+ z-index: 2
+
+ .applied.background
+ position: relative
+ z-index: 1
+
+ .background.arrow:before
+ content: ''
+ display: inline-block
+ width: 7px
+ height: 7px
+ border-style: solid
+ border-width: 2px 2px 0 0
+ border-color: $color-stickie
+ position: absolute
+ top: 0
+ right: -2px
+ vertical-align: top
+ @include transform(rotate(45deg))
+
.pinned
text-indent: -10000px
display: block
@@ -106,6 +201,11 @@
left: 1.5em
right: 1.5em
+ .count-background
+ position: absolute
+ bottom: 0
+ width: 100%
+
// Extra stickies, beyond those specified below.
// Keep in same position
.no-touch li:hover > &
@@ -162,6 +262,7 @@
.stickie.special
background-color: $color-stickie-info
+ padding: 24px 18px
.stickie.org
background-color: #fff
diff --git a/hasjob/templates/detail.html.jinja2 b/hasjob/templates/detail.html.jinja2
index 3955f869b..9ddb2c5e5 100644
--- a/hasjob/templates/detail.html.jinja2
+++ b/hasjob/templates/detail.html.jinja2
@@ -447,7 +447,16 @@
if (!triggered_related) {
triggered_related = true;
$.get("{{ post.url_for('related_posts') }}", function (data) {
- $('#stickie-area').html(data);
+ $('#stickie-area').html(data.template);
+ {%- if can_see_post_stats %}
+ window.Hasjob.Config.MaxCounts = {
+ 'max_impressions': data.max_impressions,
+ 'max_views': data.max_views,
+ 'max_opens': data.max_opens,
+ 'max_applied': data.max_applied
+ }
+ {%- endif %}
+ window.Hasjob.StickieList.init();
}
);
}
diff --git a/hasjob/templates/index.html.jinja2 b/hasjob/templates/index.html.jinja2
index c6d762090..66a463d4f 100644
--- a/hasjob/templates/index.html.jinja2
+++ b/hasjob/templates/index.html.jinja2
@@ -171,6 +171,14 @@
{%- block footerscripts -%}
{%- if not paginated -%}
diff --git a/hasjob/templates/macros.html.jinja2 b/hasjob/templates/macros.html.jinja2
index 65ad2e12e..96f427ce4 100644
--- a/hasjob/templates/macros.html.jinja2
+++ b/hasjob/templates/macros.html.jinja2
@@ -9,29 +9,46 @@
{{ post.datetime|shortdate }}
{% if is_bgroup %}{{ post.headlineb }}{% else %}{{ post.headline }}{% endif %}
{%- if show_viewcounts or show_pay %}
- {%- with post_viewcounts=get_post_viewcounts(post.id) %}
-
- {%- if show_viewcounts %}
-
- {{ post_viewcounts['impressions'] }} › {{ post_viewcounts['viewed'] }} › {{ post_viewcounts['opened'] }} › {{ post_viewcounts['applied'] }}
-
+ {%- set post_viewcounts=get_post_viewcounts(post.id) %}
+ {%- endif %}
+ {%- if show_pay %}
+ {{ post_viewcounts['pay_label'] }}
+ {%- endif %}
+
+
+ {%- if starred is not none %}
+
+ {%- endif %}
+ {%- if post.state.NEW %}
+ New!
+ {%- elif post.state.UNPUBLISHED %}
+ {{ post.state.label.title }}
{%- endif %}
- {%- if show_viewcounts and show_pay %} · {%- endif %}
- {%- if show_pay %}{{ post_viewcounts['pay_label'] }}{%- endif %}
- {%- endwith %}
- {%- endif %}
- {{ post.company_name }}
-
- {%- if starred is not none %}
-
- {%- endif %}
- {%- if post.state.NEW %}
- New!
- {%- elif post.state.UNPUBLISHED %}
- {{ post.state.label.title }}
- {%- endif %}
+ {{ post.company_name }}
+ {%- if show_viewcounts %}
+
+
+ {{ post_viewcounts['impressions'] }} impressions ›
+
+
+ {{ post_viewcounts['viewed'] }} viewed ›
+
+
+ {{ post_viewcounts['opened'] }} opened ›
+
+
+ {{ post_viewcounts['applied'] }} applied
+
+
+
+
+
+
+
+
+ {%- endif -%}
{%- if groupedunder %}
{%- else %}
diff --git a/hasjob/views/helper.py b/hasjob/views/helper.py
index ff9802ee7..45e350f31 100644
--- a/hasjob/views/helper.py
+++ b/hasjob/views/helper.py
@@ -19,13 +19,14 @@
from .. import app, redis_store, lastuser
from ..extapi import location_geodata
-from ..models import (agelimit, newlimit, db, JobCategory, JobPost, JobType, POST_STATE, BoardJobPost, Tag, JobPostTag,
+from ..models import (newlimit, db, JobCategory, JobPost, JobType, BoardJobPost, Tag, JobPostTag,
Campaign, CampaignView, CampaignAnonView, EventSessionBase, EventSession, UserEventBase, UserEvent, JobImpression,
- JobViewSession, AnonUser, campaign_event_session_table, JobLocation, PAY_TYPE)
+ JobViewSession, AnonUser, campaign_event_session_table, JobLocation, PAY_TYPE, UserJobView, JobApplication)
from ..utils import scrubemail, redactemail, cointoss
gif1x1 = 'R0lGODlhAQABAJAAAP8AAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw=='.decode('base64')
+MAX_COUNTS_KEY = u'maxcounts'
@app.route('/_sniffle.gif')
@@ -384,6 +385,24 @@ def get_post_viewcounts(jobpost_id):
return values
+def get_max_counts(postids):
+ values = g.maxcounts if 'maxcounts' in g else {}
+ if not values:
+ view_counts = [get_post_viewcounts(postid) for postid in postids]
+ values = {
+ 'max_impressions': max([vc['impressions'] for vc in view_counts] or [0]),
+ 'max_views': max([vc['viewed'] for vc in view_counts] or [0]),
+ 'max_opens': max([vc['opened'] for vc in view_counts] or [0]),
+ 'max_applied': max([vc['applied'] for vc in view_counts] or [0])
+ }
+ redis_store.hset(MAX_COUNTS_KEY, 'max_impressions', values['max_impressions'])
+ redis_store.hset(MAX_COUNTS_KEY, 'max_views', values['max_views'])
+ redis_store.hset(MAX_COUNTS_KEY, 'max_opens', values['max_opens'])
+ redis_store.hset(MAX_COUNTS_KEY, 'max_applied', values['max_applied'])
+ redis_store.expire(MAX_COUNTS_KEY, 86400)
+ return values
+
+
@app.context_processor
def inject_post_viewcounts():
return {'get_post_viewcounts': get_post_viewcounts}
@@ -391,11 +410,16 @@ def inject_post_viewcounts():
def load_viewcounts(posts):
redis_pipe = redis_store.pipeline()
- viewcounts_keys = JobPost.viewcounts_key([p.id for p in posts])
+ postids = [p.id for p in posts]
+ viewcounts_keys = JobPost.viewcounts_key(postids)
for key in viewcounts_keys:
redis_pipe.hgetall(key)
- viewcounts_values = redis_pipe.execute()
+ redis_pipe.hgetall(MAX_COUNTS_KEY)
+ values = redis_pipe.execute()
+ viewcounts_values = values[:-1]
+ maxcounts_values = values[-1]
g.viewcounts = dict(zip(viewcounts_keys, viewcounts_values))
+ g.maxcounts = maxcounts_values
def getposts(basequery=None, pinned=False, showall=False, statusfilter=None, ageless=False, limit=2000, order=True):
diff --git a/hasjob/views/index.py b/hasjob/views/index.py
index 892f4cd10..b604e297b 100644
--- a/hasjob/views/index.py
+++ b/hasjob/views/index.py
@@ -13,7 +13,7 @@
from ..models import (db, JobCategory, JobPost, JobType, POST_STATE, newlimit, agelimit, JobLocation, Board, Filterset,
Domain, Location, Tag, JobPostTag, Campaign, CAMPAIGN_POSITION, CURRENCY, JobApplication, starred_job_table, BoardJobPost)
from ..views.helper import (getposts, getallposts, gettags, location_geodata, load_viewcounts, session_jobpost_ab,
- bgroup, make_pay_graph, index_is_paginated, get_post_viewcounts)
+ bgroup, make_pay_graph, index_is_paginated, get_post_viewcounts, get_max_counts)
from ..uploads import uploaded_logos
from ..utils import string_to_number
@@ -438,8 +438,17 @@ def index(basequery=None, filters={}, md5sum=None, tag=None, domain=None, locati
if data['domain'] and data['domain'] not in db.session:
data['domain'] = db.session.merge(data['domain'])
data['show_viewcounts'] = show_viewcounts
+
+ postids = [jobpost.id for jobpost in data['posts']]
+ max_counts = get_max_counts(postids)
+ data['max_impressions'] = max_counts['max_impressions']
+ data['max_views'] = max_counts['max_views']
+ data['max_opens'] = max_counts['max_opens']
+ data['max_applied'] = max_counts['max_applied']
+
if filterset:
data['filterset'] = filterset
+
return data
diff --git a/hasjob/views/listing.py b/hasjob/views/listing.py
index 2bb671efb..82ca984ab 100644
--- a/hasjob/views/listing.py
+++ b/hasjob/views/listing.py
@@ -29,7 +29,7 @@
from hasjob.nlp import identify_language
from hasjob.views.helper import (
gif1x1, load_viewcounts, session_jobpost_ab, bgroup, has_post_stats,
- get_post_viewcounts)
+ get_post_viewcounts, get_max_counts)
@app.route('//', methods=('GET', 'POST'), subdomain='')
@@ -189,9 +189,17 @@ def job_related_posts(domain, hashid):
if is_siteadmin or (g.user and g.user.flags.get('is_employer_month')):
load_viewcounts(related_posts)
g.impressions = {rp.id: (False, rp.id, bgroup(jobpost_ab, rp)) for rp in related_posts}
- return render_template('related_posts.html.jinja2', post=post,
- related_posts=related_posts, is_siteadmin=is_siteadmin)
-
+ postids = [related_post.id for related_post in related_posts]
+ max_counts = get_max_counts(postids)
+ return jsonify(template=render_template('related_posts.html.jinja2', post=post,
+ related_posts=related_posts,
+ is_siteadmin=is_siteadmin
+ ),
+ max_impressions=max_counts['max_impressions'],
+ max_views=max_counts['max_views'],
+ max_opens=max_counts['max_opens'],
+ max_applied=max_counts['max_applied']
+ )
@app.route('///star', defaults={'domain': None}, methods=['POST'], subdomain='')
@app.route('///star', defaults={'domain': None}, methods=['POST'])