File tree Expand file tree Collapse file tree 6 files changed +112
-1
lines changed
Expand file tree Collapse file tree 6 files changed +112
-1
lines changed Original file line number Diff line number Diff line change 99from infogami import config
1010from openlibrary .core import cache
1111
12+ from . import db
13+
1214
1315class Stats :
1416 def __init__ (self , docs , key , total_key ):
@@ -175,6 +177,39 @@ def get_stats(ndays=30, use_mock_data=False):
175177 }
176178
177179
180+ def get_unique_logins_since (since_days = 30 ):
181+ since_date = datetime .datetime .now () - datetime .timedelta (days = since_days )
182+ date_str = since_date .strftime ("%Y-%m-%d" )
183+
184+ query = """
185+ SELECT COUNT(id) FROM store_index
186+ WHERE type = 'account'
187+ AND name = 'last_login'
188+ AND value > $date
189+ """
190+
191+ oldb = db .get_db ()
192+ results = list (oldb .query (query , vars = {"date" : date_str }))
193+
194+ if not results :
195+ return 0
196+ return results [0 ].get ('count' , 0 )
197+
198+
199+ def get_cached_unique_logins_since (since_days = 30 ):
200+ from openlibrary .plugins .openlibrary .home import caching_prethread
201+
202+ twelve_hours = 60 * 60 * 12
203+ key_prefix = 'logins_since'
204+ mc = cache .memcache_memoize (
205+ get_unique_logins_since ,
206+ key_prefix = key_prefix ,
207+ timeout = twelve_hours ,
208+ prethread = caching_prethread (),
209+ )
210+ return mc (since_days = since_days )
211+
212+
178213def mock_get_stats ():
179214 keyNames = [
180215 "human_edits" ,
Original file line number Diff line number Diff line change @@ -3478,6 +3478,12 @@ msgstr ""
34783478msgid "Items"
34793479msgstr ""
34803480
3481+ #: admin/index.html
3482+ msgid ""
3483+ "<span class=\" login-counts\" >0</span> patrons have logged in at least "
3484+ "once over the past 30 days."
3485+ msgstr ""
3486+
34813487#: admin/index.html
34823488msgid "Stats"
34833489msgstr ""
@@ -3614,6 +3620,14 @@ msgstr ""
36143620msgid "Borrows, last 2 years graph"
36153621msgstr ""
36163622
3623+ #: admin/index.html
3624+ msgid "Unique Logins"
3625+ msgstr ""
3626+
3627+ #: admin/index.html
3628+ msgid "Gathering login statistics..."
3629+ msgstr ""
3630+
36173631#: admin/loans_table.html
36183632msgid "BookReader"
36193633msgstr ""
Original file line number Diff line number Diff line change 2525)
2626from openlibrary .core import cache , lending , models
2727from openlibrary .core import helpers as h
28+ from openlibrary .core .admin import get_cached_unique_logins_since
2829from openlibrary .core .auth import ExpiredTokenError , HMACToken
2930from openlibrary .core .bestbook import Bestbook
3031from openlibrary .core .bookshelves_events import BookshelvesEvents
@@ -1061,3 +1062,14 @@ def make_dark(self, edition):
10611062 if not data ['source_records' ]:
10621063 del data ['source_records' ]
10631064 web .ctx .site .save (data , 'Remove OCAID: Item no longer available to borrow.' )
1065+
1066+
1067+ class monthly_logins (delegate .page ):
1068+ path = "/api/monthly_logins"
1069+ encoding = "json"
1070+
1071+ def GET (self ):
1072+ return delegate .RawText (
1073+ json .dumps ({"loginCount" : get_cached_unique_logins_since ()}),
1074+ content_type = "application/json" ,
1075+ )
Original file line number Diff line number Diff line change @@ -582,4 +582,11 @@ jQuery(function () {
582582 import ( /* webpackChunkName: "list-books" */ './list_books' )
583583 . then ( module => module . ListBooks . init ( ) ) ;
584584 }
585+
586+ // Stats page login counts
587+ const monthlyLoginStats = document . querySelector ( '.monthly-login-counts' )
588+ if ( monthlyLoginStats ) {
589+ import ( /* webpackChunkName: "stats" */ './stats' )
590+ . then ( module => module . initUniqueLoginCounts ( monthlyLoginStats ) )
591+ }
585592} ) ;
Original file line number Diff line number Diff line change 1+ /**
2+ * Fetches unique login counts and updates the view with the results.
3+ *
4+ * @param {HTMLElement } containerElem
5+ * @returns {Promise<void> }
6+ * @see /openlibrary/templates/admin/index.html
7+ */
8+ export async function initUniqueLoginCounts ( containerElem ) {
9+ const loadingIndicator = containerElem . querySelector ( '.loadingIndicator' )
10+ const i18nStrings = JSON . parse ( containerElem . dataset . i18n )
11+
12+ const counts = await fetchCounts ( )
13+ . then ( ( resp ) => {
14+ if ( resp . status !== 200 ) {
15+ throw new Error ( `Failed to fetch partials. Status code: ${ resp . status } ` )
16+ }
17+ return resp . json ( )
18+ } )
19+
20+ const countDiv = document . createElement ( 'DIV' )
21+ countDiv . innerHTML = i18nStrings . uniqueLoginsCopy
22+ const countSpan = countDiv . querySelector ( '.login-counts' )
23+ countSpan . textContent = counts . loginCount
24+ loadingIndicator . replaceWith ( countDiv )
25+ }
26+
27+ /**
28+ * Fetches login counts from the server.
29+ *
30+ * @returns {Promise<Response> }
31+ * @see `monthly_logins` class in /openlibrary/plugins/openlibrary/api.py
32+ */
33+ async function fetchCounts ( ) {
34+ return fetch ( '/api/monthly_logins.json' )
35+ }
Original file line number Diff line number Diff line change 44$ _x = ctx.setdefault('usergroup', 'admin')
55
66$ stats = get_admin_stats()
7+
8+ $ i18n_strings = {
9+ $ "uniqueLoginsCopy": _('< span class ="login-counts "> 0</ span > patrons have logged in at least once over the past 30 days.')
10+ $ }
11+
712< script type ="text/json+graph " id ="graph-json-editgraph "> $:json_encode ( counts . human_edits . get_counts ( 80 , True ) ) </ script >
813< script type ="text/json+graph " id ="graph-json-membergraph "> $:json_encode ( counts . members . get_counts ( 80 , True ) ) </ script >
914
@@ -248,5 +253,8 @@ <h2>$_("Borrows")</h2>
248253 < img alt ="$_('Borrows, last 2 years graph') " src ="https://graphite.us.archive.org/render?target=hitcount(stats.ol.loans.bookreader,%221d%22)&from=-24months&tz=UTC&width=900 "/>
249254
250255 < div class ="contentSpacer "> </ div >
251-
256+ < h2 > $_("Unique Logins")</ h2 >
257+ < div class ="monthly-login-counts " data-i18n ="$json_encode(i18n_strings) ">
258+ $:macros.LoadingIndicator(_("Gathering login statistics..."), hidden=False)
259+ </ div >
252260</ div >
You can’t perform that action at this time.
0 commit comments