Proxy URLs soon rather than late
[sitka/overdrive-evergreen-opac.git] / src / od_data.coffee
CommitLineData
9669700c
SC
1define [
2 'lodash'
3 'moment'
4], (
5 _
6 M
7) ->
8
9 # A base class defining utilitarian methods
10 class U
11 constructor: (x) ->
12 return unless x
13 t = @
14 t extends x
15 return
16
17 # Mutate an ISO 8601 date string into a Moment object. If the argument is
18 # just a date value, then it specifies an absolute date in ISO 8601 format.
19 # If the argument is a pair, then it specifies a date relative to now. For
20 # an ISO 8601 date, we correct for what seems to be an error in time zone,
21 # Zulu time is really East Coast time.
22 momentize: (date, unit) ->
23 switch arguments.length
24 when 1
25 if date then M(date.replace /Z$/, '-0400') else M()
26 when 2
27 if date then M().add date, unit else M()
28 else M()
29
508513a1
SC
30 # The URL endpoint is converted to its reverse proxy version,
31 # because we are using the Evergreen server as a reverse proxy to
32 # the Overdrive server.
33 proxy: (x) ->
34 return unless x
35 y = x
36 y = y.replace 'https://', '//'
37 y = y.replace 'http://' , '//'
38 y = y.replace '//oauth-patron.overdrive.com', '/od/oauth-patron'
39 y = y.replace '//oauth.overdrive.com', '/od/oauth'
40 y = y.replace '//patron.api.overdrive.com', '/od/api-patron'
41 y = y.replace '//api.overdrive.com', '/od/api'
42 y = y.replace '//images.contentreserve.com', '/od/images'
43 y = y.replace '//fulfill.contentreserve.com', '/od/fulfill'
44 #log "proxy #{x} -> #{y}"
45 y
46 proxies: (x) ->
47 (v.href = @proxy l) for n, v of x when l = v.href
48 return x
49
9669700c
SC
50
51 class Metadata extends U
52 constructor: (x) ->
53 super x
54
55 # Convert ID to upper case to match same case found in EG catalogue
56 @id = @id.toUpperCase()
57 # Provide a simplified notion of author: first name in creators
58 # list having a role of author
59 @author = (v.name for v in @creators when v.role is 'Author')[0] or ''
508513a1
SC
60 # Convert image links to use reverse proxy
61 @proxies @images
9669700c
SC
62
63 return
64
65
66 class Availability extends U
67 constructor: (x, email_address) ->
68 super x
69
70 @zero()
71 @hold email_address if @actions?.hold
72
73 return @
74
75 # Add zero values
76 zero: ->
77 @copiesOwned = 0 unless @copiesOwned
78 @copiesAvailable = 0 unless @copiesAvailable
79 @numberOfHolds = 0 unless @numberOfHolds
80 return @
81
82 hold: (email_address) ->
83 # The reserve ID is empty in the actions.hold.fields; we have to fill it ourselves.
84 _.where(@actions.hold.fields, name: 'reserveId')[0].value = @id
85 # We jam the email address from the prefs page into the fields object from the server
86 # so that the new form will display it.
87 if email_address
88 _.where(@actions.hold.fields, name: 'emailAddress')[0].value = email_address
89 return @
90
91
92 class Holds extends U
93 constructor: (x) ->
94 super x
95
96 @add()
97 .remove()
508513a1 98 .proxy_urls()
9669700c
SC
99 .moments()
100 .count()
101 .sort()
102
103 return
104
105 # Ensure there is always a holds list, even if it's empty
106 add: ->
107 @holds = [] if @holds is undefined
108 return @
109
110 # Delete action to release a suspension if a hold is not
111 # suspended, because such actions are redundant
112 remove: ->
113 delete x.actions.releaseSuspension for x in @holds when not x.holdSuspension
114 return @
115
508513a1
SC
116 proxy_urls: ->
117 (@proxies v.actions) for v, n in @holds
118 return @
119
9669700c
SC
120 # For each hold, convert any ISO 8601 date strings into a
121 # Moment object (at local time zone)
122 moments: ->
123 for x in @holds
124 x.holdPlacedDate = @momentize x.holdPlacedDate
125 x.holdExpires = @momentize x.holdExpires
126 if x.holdSuspension
127 x.holdSuspension.numberOfDays = @momentize x.holdSuspension.numberOfDays, 'days'
128 return @
129
130 # Count the number of holds that can be checked out now
131 count: ->
132 @ready = _.countBy @holds, (x) -> if x.actions.checkout then 'forCheckout' else 'other'
133 @ready.forCheckout = 0 unless @ready.forCheckout
134 return @
135
136 # Sort the holds list by position and placed date
137 # and sort ready holds first
138 sort: ->
139 @holds = _(@holds)
140 .sortBy ['holdListPosition', 'holdPlacedDate']
141 .sortBy (x) -> x.actions.checkout
142 .value()
143 return @
144
145
146 class Checkouts extends U
147 constructor: (x) ->
148 super x
149
150 @add()
508513a1 151 .proxy_urls()
9669700c
SC
152 .moments()
153 .sort()
154
155 return
156
157 # Ensure there is always a checkouts list, even if it's empty
158 add: ->
159 @checkouts = [] if @checkouts is undefined
160 return @
161
508513a1
SC
162 proxy_urls:->
163 (@proxies v.actions) for v, n in @checkouts
164 return @
165
9669700c
SC
166 # For each checkout, convert any ISO 8601 date strings into a
167 # Moment object (at local time zone)
168 moments: ->
169 for x in @checkouts
170 x.expires = @momentize x.expires
171 return @
172
173 # Sort the checkout list by expiration date
174 sort: ->
175 @checkouts = _.sortBy @checkouts, 'expires'
176 return @
177
178
179 class Interests
180 constructor: (h, c) ->
181 return {
182 nHolds: h.totalItems
183 nHoldsReady: h.ready.forCheckout
184 nCheckouts: c.totalItems
185 nCheckoutsReady: c.totalCheckouts
186 ofHolds: h.holds
187 ofCheckouts: c.checkouts
188 # The following property is a map from product ID to a hold or
189 # a checkout object, eg, interests.byID(124)
190 byID: do (hs = h.holds, cs = c.checkouts) ->
191 byID = {}
192 for v, n in hs
193 v.type = 'hold'
194 byID[v.reserveId] = v
195 for v, n in cs
196 v.type = 'checkout'
197 byID[v.reserveId] = v
198 return byID
199 }
200
201 return {
202 Metadata: Metadata
203 Availability: Availability
204 Holds: Holds
205 Checkouts: Checkouts
206 Interests: Interests
207 }