Skip to content

Commit 0993a7a

Browse files
committed
XWIKI-17733: Use a LiveTable to display the page liked in user profile
XWIKI-17724: Display Likers in a LiveTable * Use livetables in Likes UI * Add a new missing method to count user likes globally for allowing pagination
1 parent e64e133 commit 0993a7a

File tree

15 files changed

+298
-42
lines changed

15 files changed

+298
-42
lines changed

Diff for: xwiki-platform-core/pom.xml

+8-3
Original file line numberDiff line numberDiff line change
@@ -494,24 +494,29 @@
494494
<new>method java.util.Optional&lt;org.xwiki.ratings.Rating&gt; org.xwiki.ratings.script.AbstractScriptRatingsManager::setRating(org.xwiki.model.reference.EntityReference, int) @ org.xwiki.ratings.script.RatingsScriptService</new>
495495
<justification>Redesign of Ratings API: use new best practices for script service return if type is nullable.</justification>
496496
</item>
497-
<item>
497+
<item>
498498
<code>java.method.parameterTypeChanged</code>
499499
<old>parameter org.xwiki.ratings.script.RatingApi org.xwiki.ratings.script.RatingsScriptService::setRating(===org.xwiki.model.reference.DocumentReference===, org.xwiki.model.reference.DocumentReference, int)</old>
500500
<new>parameter java.util.Optional&lt;org.xwiki.ratings.Rating&gt; org.xwiki.ratings.script.AbstractScriptRatingsManager::setRating(===org.xwiki.model.reference.EntityReference===, org.xwiki.user.UserReference, int) @ org.xwiki.ratings.script.RatingsScriptService</new>
501501
<justification>Redesign of Ratings API: allow to set rating for any reference (not only DocumentReference)</justification>
502502
</item>
503-
<item>
503+
<item>
504504
<code>java.method.parameterTypeChanged</code>
505505
<old>parameter org.xwiki.ratings.script.RatingApi org.xwiki.ratings.script.RatingsScriptService::setRating(org.xwiki.model.reference.DocumentReference, ===org.xwiki.model.reference.DocumentReference===, int)</old>
506506
<new>parameter java.util.Optional&lt;org.xwiki.ratings.Rating&gt; org.xwiki.ratings.script.AbstractScriptRatingsManager::setRating(org.xwiki.model.reference.EntityReference, ===org.xwiki.user.UserReference===, int) @ org.xwiki.ratings.script.RatingsScriptService</new>
507507
<justification>Redesign of Ratings API: use new best practices for specifying a user by using the UserReference.</justification>
508508
</item>
509-
<item>
509+
<item>
510510
<code>java.method.returnTypeChanged</code>
511511
<old>method org.xwiki.ratings.script.RatingApi org.xwiki.ratings.script.RatingsScriptService::setRating(org.xwiki.model.reference.DocumentReference, org.xwiki.model.reference.DocumentReference, int)</old>
512512
<new>method java.util.Optional&lt;org.xwiki.ratings.Rating&gt; org.xwiki.ratings.script.AbstractScriptRatingsManager::setRating(org.xwiki.model.reference.EntityReference, org.xwiki.user.UserReference, int) @ org.xwiki.ratings.script.RatingsScriptService</new>
513513
<justification>Redesign of Ratings API: use new best practices for script service return if type is nullable.</justification>
514514
</item>
515+
<item>
516+
<code>java.method.addedToInterface</code>
517+
<new>method long org.xwiki.like.LikeManager::countUserLikes(org.xwiki.user.UserReference) throws org.xwiki.like.LikeException</new>
518+
<justification>Unstable API.</justification>
519+
</item>
515520
</revapi.ignore>
516521
</analysisConfiguration>
517522
</configuration>

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/main/java/org/xwiki/like/LikeManager.java

+13
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ public interface LikeManager
5858
*/
5959
List<EntityReference> getUserLikes(UserReference source, int offset, int limit) throws LikeException;
6060

61+
/**
62+
* Retrieve the total number of likes performed by a user.
63+
*
64+
* @param source the user who performs the likes to count.
65+
* @return the total number of likes performed.
66+
* @throws LikeException in case of problem when getting the information.
67+
* @since 12.9RC1
68+
*/
69+
@Unstable
70+
long countUserLikes(UserReference source) throws LikeException;
71+
6172
/**
6273
* Retrieve like information a specific entity.
6374
*
@@ -95,7 +106,9 @@ public interface LikeManager
95106
* @param limit the limit used for pagination.
96107
* @return a list of user references of users who liked this page.
97108
* @throws LikeException in case of problem for performing the query.
109+
* @since 12.9RC1
98110
*/
111+
@Unstable
99112
List<UserReference> getLikers(EntityReference target, int offset, int limit) throws LikeException;
100113

101114
/**

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/main/java/org/xwiki/like/internal/DefaultLikeManager.java

+13-9
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
import org.xwiki.cache.CacheManager;
3535
import org.xwiki.cache.config.LRUCacheConfiguration;
3636
import org.xwiki.component.annotation.Component;
37-
import org.xwiki.component.manager.ComponentLifecycleException;
38-
import org.xwiki.component.phase.Disposable;
3937
import org.xwiki.component.phase.Initializable;
4038
import org.xwiki.component.phase.InitializationException;
4139
import org.xwiki.like.LikeConfiguration;
@@ -65,7 +63,7 @@
6563
*/
6664
@Component
6765
@Singleton
68-
public class DefaultLikeManager implements LikeManager, Initializable, Disposable
66+
public class DefaultLikeManager implements LikeManager, Initializable
6967
{
7068
private static final int DEFAULT_LIKE_VOTE = 1;
7169

@@ -126,12 +124,6 @@ public void initialize() throws InitializationException
126124
}
127125
}
128126

129-
@Override
130-
public void dispose() throws ComponentLifecycleException
131-
{
132-
//this.authorizationManager.
133-
}
134-
135127
private String getExistCacheKey(UserReference source, EntityReference target)
136128
{
137129
return String.format("%s_%s",
@@ -176,6 +168,18 @@ public List<EntityReference> getUserLikes(UserReference source, int offset, int
176168
}
177169
}
178170

171+
@Override
172+
public long countUserLikes(UserReference source) throws LikeException
173+
{
174+
try {
175+
return this.ratingsManager.countRatings(
176+
Collections.singletonMap(RatingsManager.RatingQueryField.USER_REFERENCE, source));
177+
} catch (RatingsException e) {
178+
throw new LikeException(
179+
String.format("Error when trying to count user likes for user [%s]", source), e);
180+
}
181+
}
182+
179183
@Override
180184
public long getEntityLikes(EntityReference target) throws LikeException
181185
{

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/main/java/org/xwiki/like/script/LikeScriptService.java

+20
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,26 @@ public List<EntityReference> getUserLikes(UserReference userReference, int offse
214214
return Collections.emptyList();
215215
}
216216

217+
/**
218+
* Count the number of likes performed by the given user.
219+
*
220+
* @param userReference the user for whom to count likes.
221+
* @return the number of likes performed.
222+
* @since 12.9RC1
223+
*/
224+
@Unstable
225+
public Optional<Long> countUserLikes(UserReference userReference)
226+
{
227+
Optional<Long> result = Optional.empty();
228+
try {
229+
result = Optional.of(this.likeManager.countUserLikes(userReference));
230+
} catch (LikeException e) {
231+
this.logger.warn("Error while counting likes for user [{}]", userReference,
232+
ExceptionUtils.getRootCause(e));
233+
}
234+
return result;
235+
}
236+
217237
/**
218238
* Determine if the current user already liked the given reference.
219239
* @param entityReference the reference for which to check if the current liked it or not already.

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/main/resources/templates/likers.vm

+91-14
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,96 @@
1717
## Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
1818
## 02110-1301 USA, or see the FSF site: http://www.fsf.org.
1919
## ---------------------------------------------------------------------------
20-
#set ($likers = $services.like.getLikers($doc, 0, 50))
21-
<div id="document-title"><h1>$services.localization.render('like.likers.title', [$doc.title])</h1></div>
22-
<div id="likers-content">
23-
#if ($likers.isEmpty())
24-
$services.localization.render('like.likers.empty')
20+
#if ($request.livetable == "true")
21+
#macro (displayUserAliasWithAvatar $userReference $disabled)
22+
<div class="user#if ($disabled) disabled#end" data-reference="$escapetool.xml($userReference)">
23+
<span class="user-avatar-wrapper">
24+
#getUserAvatarURL($userReference $avatarURL 120)
25+
<img class="user-avatar" src="$escapetool.xml($avatarURL.url)" />
26+
</span>
27+
<a href="$xwiki.getURL($userReference)">$escapetool.xml($userReference.name)</a>
28+
</div>
29+
#end
30+
$response.setContentType('application/json')
31+
#set ($documentReference = $doc.documentReference)
32+
##==============================
33+
## Offset = item # at which to start displaying data
34+
##==============================
35+
#set($offset = $numbertool.toNumber($request.get('offset')))
36+
## offset starts from 0 in velocity and 1 in javascript
37+
#set($offset = $offset - 1)
38+
#if($offset < 0)
39+
#set($offset = 0)
40+
#end
41+
##==================
42+
## Limit = # of items to display
43+
##==================
44+
#set($limit = $numbertool.toNumber($request.get('limit')))
45+
##==========
46+
## Sort direction
47+
##==========
48+
#set($order = "$!request.sort")
49+
#if($order != '')
50+
#set($orderDirection = "$!{request.get('dir').toLowerCase()}")
51+
#if("$!orderDirection" != '' && "$!orderDirection" != 'asc')
52+
#set($orderDirection = 'desc')
53+
#end
54+
#end
55+
#set ($likeRecords = $services.like.getLikers($documentReference, $offset, $limit))
56+
#set ($userRows = [])
57+
#foreach($userReference in $likeRecords)
58+
#set ($grayed = $xcontext.userReference == $userReference.reference)
59+
#set ($userDoc = $xwiki.getDocument($userReference.reference))
60+
#set ($userProperties = $services.user.getProperties($userReference))
61+
#set ($userObject = $user.getObject('XWiki.XWikiUsers'))
62+
#set ($row = {
63+
'grayed': $grayed,
64+
'doc_fullName': $userDoc.fullName,
65+
'doc_wiki': $userDoc.wiki,
66+
'doc_url': $userDoc.getURL(),
67+
'doc_viewable': $services.security.authorization.hasAccess('view', $userDoc.documentReference),
68+
'name': "#displayUserAliasWithAvatar($userDoc.documentReference $disabled)",
69+
'first_name': $userProperties.firstName,
70+
'last_name': $userProperties.lastName
71+
})
72+
#set ($discard = $userRows.add($row))
73+
#end
74+
## ===
75+
## JSON
76+
## ===
77+
#set ($newOffset = $offset + 1)
78+
#set ($optLikesNumber = $services.like.getLikes($documentReference))
79+
#if ($optLikesNumber.isPresent())
80+
#set ($totalRows = $optLikesNumber.get())
2581
#else
26-
<p>
27-
$services.localization.render('like.likers.number', [$likers.size()])
28-
</p>
29-
<ul>
30-
#foreach($liker in $likers)
31-
<li>#displayUserLink($liker)</li>
32-
#end
33-
</ul>
82+
#set ($totalRows = $likeRecords.size())
3483
#end
35-
</div>
84+
{
85+
"totalrows": $totalRows,
86+
"returnedrows": $likeRecords.size(),
87+
"offset": $newOffset,
88+
"reqNo": $numbertool.toNumber($request.reqNo),
89+
"rows": $jsontool.serialize($userRows)
90+
}
91+
#else
92+
<h1>$escapetool.xml($services.localization.render('like.likers.title', [$doc.plainTitle]))</h1>
93+
#set($columns = ["name", "first_name", "last_name"])
94+
#set($columnsProperties = {
95+
"name" : { "type" : "text", "sortable": false, "filterable": false, "html": true },
96+
"first_name" : { "type" : "text", "sortable": false, "filterable": false},
97+
"last_name" : { "type" : "text", "sortable": false, "filterable": false}
98+
})
99+
#set ($queryParams = {
100+
"livetable": "true",
101+
"xpage": "likers",
102+
"outputSyntax": "plain"
103+
})
104+
## We rely on the same column name than the Users administration, so we use same translation prefix for now.
105+
#set($options = {
106+
'url': $doc.getURL('get', $escapetool.url($queryParams)),
107+
'outputOnlyHtml': true,
108+
'translationPrefix' : "xe.admin.users."
109+
})
110+
111+
#livetable("likers" $columns $columnsProperties $options)
112+
#end

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/test/java/org/xwiki/like/internal/DefaultLikeManagerTest.java

+10
Original file line numberDiff line numberDiff line change
@@ -308,4 +308,14 @@ void getLikers() throws Exception
308308
assertEquals(Arrays.asList(userReference1, userReference2, userReference3),
309309
this.defaultLikeManager.getLikers(this.target, 12, 4));
310310
}
311+
312+
@Test
313+
void countUserLikes() throws Exception
314+
{
315+
when(this.ratingsManager.countRatings(
316+
Collections.singletonMap(RatingsManager.RatingQueryField.USER_REFERENCE, this.userReference)))
317+
.thenReturn(42L);
318+
319+
assertEquals(42L, this.defaultLikeManager.countUserLikes(this.userReference));
320+
}
311321
}

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/test/java/org/xwiki/like/script/LikeScriptServiceTest.java

+20
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.xwiki.like.script;
2121

2222
import java.util.Arrays;
23+
import java.util.List;
2324
import java.util.Locale;
2425
import java.util.Optional;
2526

@@ -54,6 +55,7 @@
5455
import static org.junit.jupiter.api.Assertions.assertFalse;
5556
import static org.junit.jupiter.api.Assertions.assertSame;
5657
import static org.junit.jupiter.api.Assertions.assertTrue;
58+
import static org.mockito.Mockito.mock;
5759
import static org.mockito.Mockito.times;
5860
import static org.mockito.Mockito.verify;
5961
import static org.mockito.Mockito.when;
@@ -284,4 +286,22 @@ void cleanCache()
284286
Locale.ROOT);
285287
verify(this.asyncRendererCache).cleanCache(uixReference);
286288
}
289+
290+
@Test
291+
void countUserLikes() throws LikeException
292+
{
293+
when(this.likeManager.countUserLikes(userReference)).thenReturn(43L);
294+
assertEquals(Optional.of(43L), this.likeScriptService.countUserLikes(this.userReference));
295+
}
296+
297+
@Test
298+
void getUserLikes() throws LikeException
299+
{
300+
List<EntityReference> expectedList = Arrays.asList(
301+
mock(EntityReference.class),
302+
mock(EntityReference.class),
303+
mock(EntityReference.class));
304+
when(this.likeManager.getUserLikes(this.userReference, 2, 32)).thenReturn(expectedList);
305+
assertEquals(expectedList, this.likeScriptService.getUserLikes(this.userReference, 2, 32));
306+
}
287307
}

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.de.xml

-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,4 @@ XWiki.Like.LikeConfigurationClass_alwaysDisplayButton="Gefällt mir" Schaltfläc
5757
XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Die "Gefällt mir" Schaltfläche immer anzeigen - selbst wenn der Nutzer kein Recht hat diese zu benutzen. Anschalten, um die Anzahl der "Gefällt mir" immer anzuzeigen.
5858
XWiki.Like.LikeConfigurationClass_cacheCapacity=Cache-Größe
5959
XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Anzahl der "Gefällt mir"-Informationen im Cache. Sie müssen XWiki neustarten, damit veränderte Einstellungen angewendet werden.</content>
60-
6160
</xwikidoc>

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.es.xml

-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,4 @@ XWiki.Like.LikeConfigurationClass_alwaysDisplayButton=Mostrar siempre el botón
5757
XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Mostrar el botón incluso si el usuario no tiene derecho de interaccionar con él. Úsalo si deseas mostrar siempre el contador de "Me gusta".
5858
XWiki.Like.LikeConfigurationClass_cacheCapacity=Capacidad de la caché
5959
XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Número de información de "Me gusta" guardada en la caché. Ten en cuenta que tienes que reiniciar XWiki para que se activen los cambios de esta opción.</content>
60-
6160
</xwikidoc>

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.fr.xml

-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,4 @@ XWiki.Like.LikeConfigurationClass_alwaysDisplayButton=Toujours afficher le bouto
5757
XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Afficher le bouton même si l'utilisateur n'a pas les droits pour intéragir avec. Utilisez cette option si vous souhaitez toujours afficher le compteur de J'aime.
5858
XWiki.Like.LikeConfigurationClass_cacheCapacity=Capacité du Cache
5959
XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Nombre d'information J'aime à conserver dans le cache. Notez que vous devrez redémarrer XWiki pour que cette option soit prise en compte.</content>
60-
6160
</xwikidoc>

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.no.xml

-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,4 @@ XWiki.Like.LikeConfigurationClass_alwaysDisplayButton=Vis alltid Liker-knappen
5757
XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Vis knappen selv om brukeren ikke har rettigheter til å bruke den. Bruk hvis du alltid vil vise Liker-telleren.
5858
XWiki.Like.LikeConfigurationClass_cacheCapacity=Hurtigbufferkapasitet
5959
XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Antall Liker-informasjon som er lagret i hurtigbufferen. Merk at du må starte XWiki på nytt for at dette valget skal aktiveres.</content>
60-
6160
</xwikidoc>

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.ru.xml

-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,4 @@ like.newlike.error=Ошибка при попытке поставить "Нра
5757
### Missing: XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Display the button even if the user doesn't have the rights to interact with it. Use it if you wish to always display the Likes counter.
5858
### Missing: XWiki.Like.LikeConfigurationClass_cacheCapacity=Cache capacity
5959
### Missing: XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Number of Like information kept in cache. Note that you have to restart XWiki for this option change to be taken into account.</content>
60-
6160
</xwikidoc>

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.xml

+4-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ like.button.title.like=Click to like the current page. Number of likes on this p
5252
like.button.title.unlike=Click to unlike the current page. Number of likes on this page: {0}.
5353
like.likers.empty=No one likes this page yet.
5454
like.likers.number={0} person(s) like this page:
55-
like.likers.title=Likes on {0}
55+
like.likers.title=Likers of {0}
56+
like.livetable.column.title=Title
57+
like.livetable.column.location=Location
58+
like.livetable.column.likes=Likes
5659
XWiki.Like.LikeConfigurationClass_alwaysDisplayButton=Always display Like button
5760
XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Display the button even if the user doesn't have the rights to interact with it. Use it if you wish to always display the Likes counter.
5861
XWiki.Like.LikeConfigurationClass_cacheCapacity=Cache capacity

Diff for: xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeViewersMenuUIX.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,4 @@
183183
<scope>wiki</scope>
184184
</property>
185185
</object>
186-
</xwikidoc>
186+
</xwikidoc>

0 commit comments

Comments
 (0)