Fel uppstod under bearbetning av mallen.
The following has evaluated to null or missing: ==> crdPageUrl [in template "118468#118507#284013" at line 349, column 46] ---- Tip: If the failing expression is known to be legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)?? ---- ---- FTL stack trace ("~" means nesting-related): - Failed at: ${crdPageUrl} [in template "118468#118507#284013" at line 349, column 44] - Reached through: #assign crdPageFullUrl = "${crdPageUr... [in template "118468#118507#284013" at line 349, column 17] ----
1<#-- STAFF PICKS TEMPLATE -->
2<#--Settings needed for local REST API call -->
3<#assign portalSiteID = "" /><#-- Portal side id needed to query records -->
4<#assign agencyID = "" /><#-- Agency ID needed for cover fetching. Can be obtained e.g. from SOLR -->
5<#assign agencyMemberID = "" />
6<#assign agencyName = "" /><#-- Needed for cover fetching -->
7<#assign portNumber = "16520" /><#-- Needed for all API calls -->
8<#assign queryLimit = 8 /><#-- Limits how many records are shown at maximum in list view -->
9<#assign portalUrl = "" />
10<#assign portalUrlSecure = "" /><#-- Used for fetching covers and get rid of mixed content warning -->
11<#assign csAddress = "http://arena-central" /> <#-- used to be arena-central:16517 -->
12<#assign lsAddress = "http://arena-local:16520" />
13<#assign friendlyUrl = "" />
14<#assign sitePrefix = "/web/arena" />
15
16<#-- If friendlyUrl is not set, get it from the organization -->
17<#if friendlyUrl == "" >
18 <#assign groupLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.GroupLocalService")/>
19 <#assign group = groupLocalService.getGroup(groupId)/>
20 <#assign friendlyUrl = group.getFriendlyURL() />
21 <#assign sitePrefix = "/web${friendlyUrl}" />
22</#if>
23
24<#-- Get server and page URLs -->
25<#assign serviceContext = staticUtil["com.liferay.portal.kernel.service.ServiceContextThreadLocal"].getServiceContext() />
26<#assign themeDisplay = serviceContext.getThemeDisplay() />
27<#assign portalUrl = themeDisplay.getPortalURL() />
28<#assign portalUrlSecure = portalUrl />
29<#if portalUrlSecure?index_of("https") == -1>
30 <#assign portalUrlSecure = portalUrl?replace("http", "https") />
31</#if>
32<#if portalUrl?index_of("https") != -1>
33 <#assign portalUrl = portalUrl?replace("https", "http") />
34</#if>
35
36<#assign virtualURL = portalUrlSecure?replace("https://","") />
37
38<#assign fullPageUrl = portalUrl + themeDisplay.getURLCurrent() />
39<#assign urlMatcher = themeDisplay.getURLCurrent()?matches("^(/[a-z]{2}(_[A-Z]{2})?)?/web/[^/]+")>
40<#list urlMatcher as algFriendlyUrl>
41 <#assign crdPageUrl = portalUrlSecure + algFriendlyUrl + "/results"/>
42 <#assign searchPageUrl = portalUrlSecure + algFriendlyUrl + "/search"/>
43</#list>
44
45<#-- General variables needed in multiple macros -->
46<#assign journalArticleResourceService = serviceLocator.findService("com.liferay.journal.service.JournalArticleResourceLocalService") />
47<#assign articleResourcePK = journalArticleResourceService.getArticleResourcePrimKey(groupId, .vars['reserved-article-id'].data)?number />
48<#assign journalArticleService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
49<#assign journalArticle = journalArticleService.getArticle(groupId, .vars['reserved-article-id'].data) />
50
51<#--Makes a query to the REST API and requests records. This function should be used to call the API within this template.
52Returns the result as a simpleHash object -->
53<#function queryAPI query limit>
54 <#assign fullRequestUrl = "${lsAddress}/local-rest/api/v1/portalsites/${portalSiteID}/records?query=${httpUtilUnsafe.encodeURL(query)}&count=${limit}&isShowExtended=false&sortDirection=Descending&sortField=Relevance&agencyMemberId=${agencyMemberID}&decorationNames=Ratings"/>
55 <#assign response = httpUtilUnsafe.URLtoString(fullRequestUrl) />
56 <#assign result = jsonFactoryUtil.looseDeserialize(response) />
57 <#return result />
58</#function>
59
60<#-- Makes a query to Central REST API to get portal site settings -->
61<#function getPortalSiteSettingsFromCentralService>
62 <#assign requestUrlPortalSites = "${csAddress}/central-rest/api/v1/configs/portalsites?vhost=${httpUtilUnsafe.encodeURL(virtualURL)}&friendlyUrl=${httpUtilUnsafe.encodeURL(friendlyUrl)}" />
63 <#assign response = httpUtilUnsafe.URLtoString(requestUrlPortalSites) />
64 <#assign result = jsonFactoryUtil.looseDeserialize(response) />
65 <#return result />
66</#function>
67
68<#-- Makes a query to Central REST API to get Member settings to extract Agency ID from -->
69<#function getAgencySettingsFromCentralService>
70 <#assign requestUrlMemberAgencies = "${csAddress}/central-rest/api/v1/configs/agencymembers/${agencyMemberID}" />
71 <#assign response = httpUtilUnsafe.URLtoString(requestUrlMemberAgencies) />
72 <#assign result = jsonFactoryUtil.looseDeserialize(response) />
73 <#return result />
74</#function>
75
76<#function getServerSettingsFromCentralService>
77 <#assign portalSites = "" />
78 <#assign returnValue = "OK" />
79 <#assign portalSites = "" />
80 <#assign memberData = "" />
81 <#assign favoriteAgencyName = "" />
82 <#attempt>
83 <#assign portalSites = getPortalSiteSettingsFromCentralService() />
84 <#if portalSites.id??>
85 <#assign portalSiteID = portalSites.id?string />
86 <#assign favoriteAgencyName = portalSites.mainGroup.properties["Favourite Agency Member"] />
87 <#else>
88 <#assign requestUrlPortalSites = "${csAddress}/central-rest/api/v1/configs/portalsites?vhost=${httpUtilUnsafe.encodeURL(virtualURL)}&friendlyUrl=${httpUtilUnsafe.encodeURL(friendlyUrl)}" />
89 <#assign response = httpUtilUnsafe.URLtoString(requestUrlPortalSites) />
90 </#if>
91 <#if favoriteAgencyName != "">
92 <#-- Go through portalSites.agencyMemberSummaries to find the one with matching favoriteAgencyName -->
93 <#list portalSites.agencyMemberSummaries as summary>
94 <#if summary.name == favoriteAgencyName>
95 <#assign agencyMemberID = summary.id?string />
96 </#if>
97 </#list>
98 </#if>
99 <#recover>
100 <#assign returnValue = "Portal Sites failed" />
101 </#attempt>
102 <#if agencyMemberID != "" && returnValue == "OK">
103 <#attempt>
104 <#assign memberData = getAgencySettingsFromCentralService() />
105 <#if memberData.agency??>
106 <#assign agencyID = memberData.agency.id />
107 <#assign agencyName = memberData.agency.name />
108 </#if>
109 <#recover>
110 <#assign returnValue = "Agency member data failed" />
111 </#attempt>
112 </#if>
113
114 <#return returnValue />
115</#function>
116
117<#macro debugServerInfo>
118 <div class="serverInfo hidden debug informative">
119 <p class="idsForRestAPI">
120 <strong>Portal Site ID:</strong> ${portalSiteID}<br />
121 <strong>Agency ID:</strong> ${agencyID}<br />
122 <strong>Agency name:</strong> ${agencyName}<br />
123 <strong>Member ID:</strong> ${agencyMemberID}
124
125 </p>
126 <p class="serverURL">
127 <strong>Portal site URL:</strong> ${portalUrl}<br />
128 <strong>Portal site URL Secure:</strong> ${portalUrlSecure}<br />
129 <strong>Virtual URL:</strong> ${virtualURL}<br />
130 <strong>Friendly URL:</strong> ${friendlyUrl}
131 </p>
132 </div>
133</#macro>
134
135<#-- Outputs a hidden debug tag with information. -->
136<#macro debugthis title message link isinformative>
137 <#assign cssClass = "hidden debug" />
138 <#if isinformative>
139 <#assign cssClass = "hidden debug informative" />
140 </#if>
141 <div class="${cssClass}">
142 <h4>Debug - ${title}</h4>
143 <#if link == "">
144 <p>${message}</p>
145 <#else>
146 <p><a href="${link}">${message}</a></p>
147 </#if>
148 </div>
149</#macro>
150
151<#macro showTags>
152 <#assign tagsService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetTagLocalService") />
153 <#assign tagsAsset = tagsService.getTags("com.liferay.journal.model.JournalArticle", articleResourcePK) />
154
155<#-- Services for tag links -->
156 <#assign layoutUid = journalArticle.getLayoutUuid() />
157
158 <h3><@liferay.language key="staffpicks.detail.header.tags" /></h3>
159 <@debugthis title="tags" message="Tag links don't work yet." isinformative=true link="" />
160 <@debugthis title="tags" message=layoutUid isinformative=true link="" />
161 <ul class="staffpick-article-tags">
162 <#list tagsAsset as tag>
163 <#assign tagNameLink = tag.getName() />
164 <li class="staffpick-article-tagentry"><a class="staffpicks-article-tag-link" href="${sitePrefix}/-/tag/${tagNameLink}">${tagNameLink}</a></li>
165 </#list>
166 </ul>
167</#macro>
168
169<#macro showArticleAuthor>
170 <#if articleAuthor?? && articleAuthor.getData() != "">
171 <p class="staffpick-article-author-name">
172 <@liferay.language_format key="staffpicks.detail.articleauthor" arguments=[articleAuthor.getData()] />
173 <#--${languageUtil.format(locale, "staffpicks.detail.articleauthor", [articleAuthor.getData()])}-->
174 </p>
175 </#if>
176</#macro>
177
178<#macro showDate dateString>
179 <#assign localization = languageUtil.get(locale,"staffpicks.detail.dateformat") />
180 <#assign timeString = "MMM d yyyy" />
181 <#if localization != "staffpicks.detail.dateformat">
182 <#assign timeString = localization />
183 </#if>
184 <#assign originalLocale = locale />
185 <#setting locale = localeUtil.getDefault() />
186 <#assign time = dateString?datetime("EEE, dd MMM yyyy hh:mm:ss ZZZZ") />
187 <#setting locale = originalLocale />
188 ${time?string[timeString]}
189</#macro>
190
191<#macro showRecord recordInfo>
192<#-- Arena 4 CRD link -->
193 <#assign crdPageFullUrl = "${crdPageUrl}?p_p_id=crDetailWicket_WAR_arenaportlet&p_p_lifecycle=1&p_p_state=normal&p_r_p_arena_urn%3Aarena_search_item_id=${recordInfo.id}&p_r_p_arena_urn%3Aarena_agency_name=${agencyName}" />
194
195 <li class="similar-record record-${recordInfo.id}">
196 <@debugthis title="Record" message="ID: ${recordInfo.id}" link="" isinformative=true />
197 <a class="similar-record-link" href="${crdPageFullUrl}">
198 <img class="similar-record-cover" src="${portalUrlSecure}/local-rest/api/v1/portalsites/${portalSiteID}/agencies/${agencyID}/records/${httpUtilUnsafe.encodeURL(recordInfo.id)}/cover" alt="" />
199 <span class="similar-record-title">${recordInfo.fields.title}</span>
200 <#if recordInfo.fields.authors?? && recordInfo.fields.authors?size gt 0 && recordInfo.fields.authors[0]??>
201 <span class="similar-record-author">${recordInfo.fields.authors[0].name}
202 </#if>
203 </a>
204 <#if recordInfo.rating??>
205 <@showRatings rating=recordInfo.rating recordtitle=recordInfo.fields.title />
206 </#if>
207 </li>
208</#macro>
209
210<#macro showRatings rating recordtitle>
211 <#assign ratingFive = (rating/2) />
212 <#assign ratingLimit = 5 />
213 <div class="staffpicks-rating">
214 <#assign ratingFiveString = ratingFive?string.number />
215 <span class="sr-only"><@liferay.language_format key="staffpicks.detail.rating" arguments=[recordtitle, ratingFiveString, ratingLimit]/></span>
216 <#list 1..ratingLimit as x>
217 <#if (x-0.5) == ratingFive>
218 <span class="arena-rating rating-half-full"><i class="icon-star-half-full"></i></span>
219 <#elseif x <= ratingFive>
220 <span class="arena-rating rating-full"><i class="icon-star"></i></span>
221 <#else>
222 <span class="arena-rating rating-empty"><i class="icon-star-empty"></i></span>
223 </#if>
224 </#list>
225 </div>
226</#macro>
227
228<#macro showSimilarRecords result>
229 <h3><@liferay.language key="staffpicks.detail.header.similartitles" /></h3>
230 <#assign searchString = "" />
231 <#attempt>
232 <#if result.fields.subjects?size gt 0>
233 <#assign searchString = searchString + "(" />
234 <#list result.fields.subjects as subject>
235 <#assign searchString = searchString + "subject:\"${subject}\"" />
236 <#if subject_index < result.fields.subjects?size-1>
237 <#assign searchString = searchString + " OR " />
238 </#if>
239 </#list>
240 <#assign searchString = searchString +") AND (" />
241 <#else>
242 <#assign searchString = searchString +"(" />
243 </#if>
244 <#recover>
245 </#attempt>
246 <#attempt>
247 <#if result.fields.languages?size gt 0>
248 <#list result.fields.languages as language>
249 <#assign searchString = searchString + "language:\"${language}\"" />
250 <#if language_index < result.fields.languages?size-1>
251 <#assign searchString = searchString + " OR " />
252 </#if>
253 </#list>
254 </#if>
255 <#recover>
256 </#attempt>
257 <#attempt>
258 <#assign searchString = searchString +") AND " />
259 <#assign searchString = searchString+"mediaclass:\"${result.fields.mediaClass}\" AND " />
260 <#assign searchString = searchString +"NOT uberkey:\"${result.uberkey}\"" />
261 <#recover>
262 </#attempt>
263
264 <#assign similarBooks = "">
265
266 <#attempt>
267 <#assign similarBooks = queryAPI(searchString, queryLimit) />
268 <ul class="staffpick-similar-records">
269 <#list similarBooks.records as record>
270 <@showRecord recordInfo = record />
271 </#list>
272 </ul>
273 <#recover>
274 <@debugthis title="Similar records" message="Similar records not looked for because an error happened in API call or processing it." isinformative=false link="" />
275 </#attempt>
276 <@debugthis title="Similar records search string" message=searchString isinformative=true link="" />
277 <#assign fullRequestUrl = '${lsAddress}/local-rest/api/v1/portalsites/${portalSiteID}/records?query=${searchString}&count=${queryLimit}&isShowExtended=false&sortDirection=Descending&sortField=Relevance&agencyMemberId=${agencyMemberID}'/>
278 <@debugthis title="Similar records search URL" message="Similar records query" isinformative=true link=fullRequestUrl />
279</#macro>
280
281<#-- Prints a debug button that toggles the visibility of elements with debug CSS class -->
282<#macro toggleDebug>
283 <script type="text/javascript">
284 function toggleDebugMessages() {
285 YUI().use("node",function(Y) {
286 Y.all(".debug").each(function() {
287 this.toggleClass("hidden");
288 });
289 });
290 };
291 </script>
292 <a href="javascript:void(0);" onclick="toggleDebugMessages()" class="btn btn-info toggle-debug-button"><i class="icon-eye-open"></i> Debug</a>
293</#macro>
294
295<link rel="stylesheet" type="text/css" href="//cdn.axiell.com/arena/staffpicks/staffpicks.css">
296<div class="staffpick-article">
297 <#assign status = "OK" />
298 <#assign status = getServerSettingsFromCentralService() />
299
300 <@debugServerInfo />
301
302 <#if status != "OK">
303 <@debugthis isinformative=false title="Central Service Settings failed" message="Failed with ${status}" link=""/>
304 </#if>
305
306 <div class="back-button-container">
307 <a class="staffpick-back-link" href="javascript:void(0);" onclick="window.history.back();"><@liferay.language key="back" /></a>
308 </div>
309 <style>.portlet-asset-categories-navigation, .staff-picks-introduction { display: none; }</style>
310 <#assign searchQuery = "" />
311 <#assign result = "" />
312 <#assign recordInfo = "" />
313 <#if recordId?? && recordId.getData() != "">
314 <#if recordId.getData()?index_of("id:") == -1>
315 <#assign searchQuery = 'id:"${recordId.getData()}"' />
316 <#else>
317 <#assign searchQuery = recordId.getData() />
318 </#if>
319 <#attempt>
320 <#assign result = queryAPI(searchQuery, 1) />
321 <#assign recordInfo = result.records[0] />
322
323 <#recover>
324 <#assign recordInfo = {
325 "fields" : {
326 "title" : "${.vars['reserved-article-title'].data}"
327 }
328 } />
329 <#assign fullRequestUrl = "${lsAddress}/local-rest/api/v1/portalsites/${portalSiteID}/records?query=${httpUtilUnsafe.encodeURL(searchQuery,true)}&count=1&isShowExtended=false&sortDirection=Descending&sortField=Relevance&agencyMemberId=${agencyMemberID}"/>
330 <@debugthis isinformative=false title="API call failed with this url" message=fullRequestUrl link=fullRequestUrl />
331
332 </#attempt>
333 <#else>
334 <#assign recordInfo = {
335 "fields" : {
336 "title" : "${.vars['reserved-article-title'].data}"
337 }
338 } />
339 </#if>
340
341
342
343
344 <div class="row">
345 <div class="col-xs-12 col-sm-4 col-lg-3 cover-column">
346
347 <#if recordInfo.id??>
348 <#--Arena 4 CRD link -->
349 <#assign crdPageFullUrl = "${crdPageUrl}?p_p_id=crDetailWicket_WAR_arenaportlet&p_p_lifecycle=1&p_p_state=normal&p_r_p_arena_urn%3Aarena_search_item_id=${recordInfo.id}&p_r_p_arena_urn%3Aarena_agency_name=${agencyName}" />
350
351 <a class="record-link" href="${crdPageFullUrl}">
352 <#assign assetService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
353 <#assign thumbnailPath = "" />
354 <#attempt>
355 <#assign serviceContext = staticUtil["com.liferay.portal.kernel.service.ServiceContextThreadLocal"].getServiceContext()>
356 <#assign themeDisplay = serviceContext.getThemeDisplay() />
357 <#assign thumbnailPath = journalArticle.getArticleImageURL(themeDisplay) />
358 <#recover>
359 </#attempt>
360 <#if journalArticle.getSmallImage() && thumbnailPath != "">
361 <img class="cover-image cover-overwrite" alt="" src="${thumbnailPath}" />
362 <#else>
363 <img class="cover-image" alt="" src="${portalUrlSecure}/local-rest/api/v1/portalsites/${portalSiteID}/agencies/${agencyID}/records/${httpUtilUnsafe.encodeURL(recordInfo.id)}/cover" />
364 </#if>
365 <span class="alg-button alg-button--inverted gotoCRDButton"><@liferay.language key="staffpicks.detail.viewbook" /></span>
366 </a>
367 </#if>
368 <@toggleDebug />
369 </div>
370 <div class="col-xs-12 col-sm-8 col-lg-9 staffpick-detail">
371 <div class="staffpick-article-title">
372 <h2>${recordInfo.fields.title}</h2>
373 </div>
374 <#-- Special debug which cannot be in a regular macro -->
375 <#if recordInfo.id??>
376 <@debugthis title="Record Id - API" message="Record ID from API: ${recordInfo.id}" isinformative=true link="" />
377 </#if>
378 <@debugthis title="Record Id - Query" message="Record ID from Query: ${recordId.getData()}" isinformative=true link="" />
379 <#if recordInfo.id?? && (recordInfo.id != recordId.getData() )>
380 <@debugthis title="Record id missmatch" message="Query ID and API ID do not match!" isinformative=false link="" />
381 </#if>
382
383 <#if recordInfo.fields?? && recordInfo.fields.authors?? && recordInfo.fields.authors?size gt 0 && recordInfo.fields.authors[0]??>
384 <div class="staffpick-article-author">
385 <a class="staffpick-article-author-link" href="${searchPageUrl}?p_p_id=searchResult_WAR_arenaportlet&p_p_lifecycle=1&p_p_state=normal&p_r_p_arena_urn%3Aarena_facet_queries=&p_r_p_arena_urn%3Aarena_search_query=${recordInfo.fields.authors[0].name}&p_r_p_arena_urn%3Aarena_search_type=solr&p_r_p_arena_urn%3Aarena_sort_advice=field%3DRelevance%26direction%3DDescending">
386 <@liferay.language_format key="staffpicks.detail.author" arguments=[recordInfo.fields.authors[0].name] />
387 </a>
388 </div>
389 </#if>
390 <div class="staffpick-article-text">
391 ${articleText.getData()}
392 </div>
393 <div class="staffpick-article-recommendedby-date row">
394 <div class="staffpick-article-recommeded-by col-xs-12 col-sm-7">
395 <@showArticleAuthor />
396 </div>
397 <div class="staffpick-article-date col-xs-12 col-sm-5">
398 <@showDate dateString=.vars['reserved-article-create-date'].data />
399 </div>
400 </div>
401 </div>
402 </div>
403 <#--<div class="row tags-container">
404 <div class="col-xs-12">
405 <@showTags />
406 </div>
407 </div>-->
408 <div class="row similar-records-container">
409 <div class="col-xs-12">
410 <@showSimilarRecords result=recordInfo />
411 </div>
412 </div>
413</div>