Skip to content

Commit b0d6eff

Browse files
committed
implement removal of workshop ratings
1 parent 6dea66c commit b0d6eff

File tree

6 files changed

+368
-125
lines changed

6 files changed

+368
-125
lines changed

app/routes.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@
160160
// Workshop item rate
161161
$group->post('/rate/{id:\d+}/quality', [Workshop\WorkshopRatingController::class, 'rateQuality'])->add(LoggedInMiddleware::class);
162162
$group->post('/rate/{id:\d+}/difficulty', [Workshop\WorkshopRatingController::class, 'rateDifficulty'])->add(LoggedInMiddleware::class);
163+
$group->post('/rate/{id:\d+}/quality/remove', [Workshop\WorkshopRatingController::class, 'removeQualityRating'])->add(LoggedInMiddleware::class);
164+
$group->post('/rate/{id:\d+}/difficulty/remove', [Workshop\WorkshopRatingController::class, 'removeDifficultyRating'])->add(LoggedInMiddleware::class);
163165

164166
// Workshop item comment
165167
$group->post('/item/{id:\d+}/comment', [Workshop\WorkshopCommentController::class, 'comment'])->add(LoggedInMiddleware::class);

controllers/Workshop/WorkshopRatingController.php

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,5 +198,165 @@ public function rateDifficulty(
198198
return $response;
199199
}
200200

201+
public function removeQualityRating(
202+
Request $request,
203+
Response $response,
204+
Account $account,
205+
EntityManager $em,
206+
CsrfGuard $csrf_guard,
207+
WorkshopRatingTwigExtension $workshop_rating_extension,
208+
$id
209+
)
210+
{
211+
// Check if workshop item exists
212+
$workshop_item = $em->getRepository(WorkshopItem::class)->find($id);
213+
if(!$workshop_item){
214+
return $response;
215+
}
216+
217+
// Get rating
218+
$rating = $em->getRepository(WorkshopRating::class)->findOneBy([
219+
'item' => $workshop_item,
220+
'user' => $account->getUser()
221+
]);
222+
if(!$rating) {
223+
$response->getBody()->write(
224+
\json_encode([
225+
'success' => false,
226+
'error' => 'Rating not found',
227+
'csrf' => [
228+
'keys' => [
229+
'name' => $csrf_guard->getTokenNameKey(),
230+
'value' => $csrf_guard->getTokenValueKey(),
231+
],
232+
'name' => $csrf_guard->getTokenName(),
233+
'value' => $csrf_guard->getTokenValue()
234+
],
235+
])
236+
);
237+
return $response;
238+
}
239+
240+
// Remove rating
241+
$em->remove($rating);
242+
$em->flush();
243+
244+
// Get updated rating
245+
$rating_score = null;
246+
$ratings = $workshop_item->getRatings();
247+
if($ratings && \count($ratings) > 0){
248+
$rating_scores = [];
249+
foreach($ratings as $rating){
250+
$rating_scores[] = $rating->getScore();
251+
}
252+
$rating_average = \array_sum($rating_scores) / \count($rating_scores);
253+
$rating_score = \round($rating_average, 2);
254+
}
255+
256+
// Set updated rating in item
257+
// This way we don't always have to calculate the rating when doing stuff like
258+
// ordering workshop items by rating score
259+
$workshop_item->setRatingScore($rating_score);
260+
$em->flush();
261+
262+
// Return
263+
$response->getBody()->write(
264+
\json_encode([
265+
'success' => true,
266+
'rating_score' => $rating_score,
267+
'rating_count' => \count($ratings),
268+
'html' => $workshop_rating_extension->renderWorkshopQualityRating($id, $rating_score),
269+
'csrf' => [
270+
'keys' => [
271+
'name' => $csrf_guard->getTokenNameKey(),
272+
'value' => $csrf_guard->getTokenValueKey(),
273+
],
274+
'name' => $csrf_guard->getTokenName(),
275+
'value' => $csrf_guard->getTokenValue()
276+
],
277+
])
278+
);
279+
return $response;
280+
}
201281

282+
public function removeDifficultyRating(
283+
Request $request,
284+
Response $response,
285+
Account $account,
286+
EntityManager $em,
287+
CsrfGuard $csrf_guard,
288+
WorkshopRatingTwigExtension $workshop_rating_extension,
289+
$id
290+
)
291+
{
292+
// Check if workshop item exists
293+
$workshop_item = $em->getRepository(WorkshopItem::class)->find($id);
294+
if(!$workshop_item){
295+
return $response;
296+
}
297+
298+
// Get rating
299+
$rating = $em->getRepository(WorkshopDifficultyRating::class)->findOneBy([
300+
'item' => $workshop_item,
301+
'user' => $account->getUser()
302+
]);
303+
if(!$rating) {
304+
$response->getBody()->write(
305+
\json_encode([
306+
'success' => false,
307+
'error' => 'Rating not found',
308+
'csrf' => [
309+
'keys' => [
310+
'name' => $csrf_guard->getTokenNameKey(),
311+
'value' => $csrf_guard->getTokenValueKey(),
312+
],
313+
'name' => $csrf_guard->getTokenName(),
314+
'value' => $csrf_guard->getTokenValue()
315+
],
316+
])
317+
);
318+
return $response;
319+
}
320+
321+
// Remove rating
322+
$em->remove($rating);
323+
$em->flush();
324+
325+
// Get updated rating
326+
$rating_score = null;
327+
$ratings = $workshop_item->getDifficultyRatings();
328+
if($ratings && \count($ratings) > 0){
329+
$rating_scores = [];
330+
foreach($ratings as $rating){
331+
$rating_scores[] = $rating->getScore();
332+
}
333+
$rating_average = \array_sum($rating_scores) / \count($rating_scores);
334+
$rating_score = \round($rating_average, 2);
335+
}
336+
337+
// Set updated rating in item
338+
// This way we don't always have to calculate the rating when doing stuff like
339+
// ordering workshop items by rating score
340+
$workshop_item->setDifficultyRatingScore($rating_score);
341+
$em->flush();
342+
343+
// Return
344+
$response->getBody()->write(
345+
\json_encode([
346+
'success' => true,
347+
'rating_score' => $rating_score,
348+
'rating_count' => \count($ratings),
349+
'html' => $workshop_rating_extension->renderWorkshopDifficultyRating($id, $rating_score),
350+
'csrf' => [
351+
'keys' => [
352+
'name' => $csrf_guard->getTokenNameKey(),
353+
'value' => $csrf_guard->getTokenValueKey(),
354+
],
355+
'name' => $csrf_guard->getTokenName(),
356+
'value' => $csrf_guard->getTokenValue()
357+
],
358+
])
359+
);
360+
return $response;
361+
}
202362
}

public/css/theme.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,17 @@ footer {
626626
grid-row: 1 / 4;
627627
}
628628

629+
#difficulty-rating-info .rating-remove,
630+
#quality-rating-info .rating-remove {
631+
margin-left: 3px;
632+
display: none;
633+
}
634+
635+
#difficulty-rating-info:hover .rating-remove,
636+
#quality-rating-info:hover .rating-remove {
637+
display: inline-block;
638+
}
639+
629640
.btn-download-filename {
630641
display: block;
631642
position: relative;

public/js/workshop.item.js

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
2+
3+
function handleRatingHtml(el){
4+
5+
var $ratingBox = $(el);
6+
var ratingType = $ratingBox.attr('data-workshop-rating-type');
7+
8+
$.each($(el).find('img'), function(index, element){
9+
10+
var ratingScore = parseInt($(element).attr('data-rating-score'));
11+
12+
$(element).css('cursor', 'pointer');
13+
14+
$(element).on('click', function(e){
15+
16+
// Hide open popover
17+
$('.popover').hide();
18+
19+
// Make sure we are logged in
20+
if(app_store.account === null){
21+
window.location = '/login'
22+
+ '?redirect=/workshop/item/' + workshop_item.id + '/' + workshop_item.slug
23+
+ '&msg=workshop-rate';
24+
return;
25+
}
26+
27+
// Disable rating own account items
28+
if(ratingType === 'quality' && app_store.account.id === workshop_item.submitter_id){
29+
toastr.warning('You can not rate your own workshop items!');
30+
return;
31+
}
32+
33+
// Rate the workshop item
34+
$.ajax({
35+
type: 'POST',
36+
url: '/workshop/rate/' + workshop_item.id + '/' + ratingType,
37+
data: {
38+
score: ratingScore,
39+
[app_store.csrf.keys.name]: app_store.csrf.name,
40+
[app_store.csrf.keys.value]: app_store.csrf.value
41+
},
42+
dataType: 'json', // return type data,
43+
error: function(data){
44+
toastr.error('Something went wrong.');
45+
},
46+
success: function(data){
47+
48+
// Make sure rating went successful
49+
if(typeof data.success === 'undefined' || data.success !== true){
50+
toastr.error('Something went wrong.');
51+
return;
52+
}
53+
54+
// Update rating stars HTML
55+
$ratingBox.html(data.html);
56+
handleRatingHtml($ratingBox);
57+
58+
// Set template for rating info
59+
$('#' + ratingType + '-rating-info').html('<span id="' + ratingType + '-rating-score" class="text-muted"></span> / 5' +
60+
'<span style="margin: 0 3px" class="text-muted"> &bull; </span>' +
61+
'<span id="' + ratingType + '-rating-count" class="text-muted"></span>' +
62+
'<span style="margin: 0 3px" class="text-muted"> &bull; </span>' +
63+
'Your rating: ' +
64+
'<span id="' + ratingType + '-rating-self" class="text-muted"></span> ' + // needs a space at the end
65+
'<a href="#" data-workshop-rating-type="' + ratingType + '" class="rating-remove text-stand-out">Remove</a>'
66+
);
67+
68+
// Update rating score
69+
$('#' + ratingType + '-rating-score').text(data.rating_score);
70+
71+
// Update rating count
72+
if(data.rating_count === 1){
73+
$('#' + ratingType + '-rating-count').text('1 rating');
74+
} else {
75+
$('#' + ratingType + '-rating-count').text('' + data.rating_count + ' ratings');
76+
}
77+
78+
// Update self rating
79+
$('#' + ratingType + '-rating-self').text(ratingScore);
80+
81+
// Update CSRF tokens
82+
app_store.csrf.name = data.csrf.name;
83+
app_store.csrf.value = data.csrf.value;
84+
85+
toastr.success('You have successfully rated this workshop item!');
86+
87+
},
88+
});
89+
});
90+
91+
new bootstrap.Popover(element, {
92+
'placement': 'top',
93+
'trigger': 'hover',
94+
'content': 'Rate this item ' + ratingScore + ' out of 5'
95+
});
96+
});
97+
}
98+
99+
$(function(e){
100+
101+
// Render workshop ratings
102+
$.each($('[data-workshop-rating-type]'), function(i, el){
103+
handleRatingHtml(el);
104+
});
105+
106+
// Show 'Show all downloads' and hide 'Downloads list'
107+
// This is users with javascript disabled can still view all files
108+
$('#show-all-downloads').show();
109+
$('#all-downloads-list').hide();
110+
111+
// Handle 'Show all downloads'
112+
$('#show-all-downloads a').on('click', function(e){
113+
e.preventDefault();
114+
if($('#all-downloads-list').is(':visible') === true){
115+
$(this).text('Show all downloads (' + $('#all-downloads-list tbody tr').length + ')');
116+
$('#all-downloads-list').slideUp("fast");
117+
} else if($('#all-downloads-list').is(':visible') === false) {
118+
$(this).text('Hide all downloads (' + $('#all-downloads-list tbody tr').length + ')');
119+
$('#all-downloads-list').slideDown("fast");
120+
}
121+
});
122+
123+
// Handle remove rating
124+
$('body').on('click', function(e){
125+
126+
let $target = $(e.target);
127+
if(!$target.hasClass('rating-remove')){
128+
return true;
129+
}
130+
131+
e.preventDefault();
132+
133+
var ratingType = $target.attr('data-workshop-rating-type');
134+
var $ratingBox = $target.parent().parent().parent().find('span:first');
135+
136+
// Rate the workshop item
137+
$.ajax({
138+
type: 'POST',
139+
url: '/workshop/rate/' + workshop_item.id + '/' + ratingType + '/remove',
140+
data: {
141+
[app_store.csrf.keys.name]: app_store.csrf.name,
142+
[app_store.csrf.keys.value]: app_store.csrf.value
143+
},
144+
dataType: 'json', // return type data,
145+
error: function(data){
146+
toastr.error('Something went wrong.');
147+
},
148+
success: function(data){
149+
150+
// Make sure rating went successful
151+
if(typeof data.success === 'undefined' || data.success !== true){
152+
toastr.error('Something went wrong.');
153+
return;
154+
}
155+
156+
// Update rating stars HTML
157+
$ratingBox.html(data.html);
158+
handleRatingHtml($ratingBox);
159+
160+
if(data.rating_count === 0){
161+
$('#' + ratingType + '-rating-info').text('Not rated yet');
162+
} else {
163+
// Set template for rating info
164+
$('#' + ratingType + '-rating-info').html('<span id="' + ratingType + '-rating-score" class="text-muted"></span> out of 5' +
165+
'<span style="margin: 0 3px" class="text-muted"> &bull; </span>' +
166+
'<span id="' + ratingType + '-rating-count" class="text-muted"></span>'
167+
);
168+
169+
// Update rating score
170+
$('#' + ratingType + '-rating-score').text(data.rating_score);
171+
172+
// Update rating count
173+
if(data.rating_count === 1){
174+
$('#' + ratingType + '-rating-count').text('1 rating');
175+
} else {
176+
$('#' + ratingType + '-rating-count').text('' + data.rating_count + ' ratings');
177+
}
178+
}
179+
180+
// Update CSRF tokens
181+
app_store.csrf.name = data.csrf.name;
182+
app_store.csrf.value = data.csrf.value;
183+
184+
toastr.success('You have successfully removed your rating for this workshop item.');
185+
186+
},
187+
});
188+
});
189+
});

public/js/workshop.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ $(function(){
120120
},
121121
success: function(data){
122122

123-
// Make sure rating went successful
123+
// Make sure request went successful
124124
if(typeof data.success === 'undefined' || data.success !== true){
125125
toastr.error('Something went wrong.');
126126
return;

0 commit comments

Comments
 (0)