
notification: Introduce WatchService.
You can implement Watch feature for any Resource with the WatchService. WatchService absorbs many facilities which originally Issue, Posting, Commit and Project had for providing watching feature. To do that, this commit make some changes on Resource as below: * The type of Resource's id has changed from Long to String. * ResourceParam, which implements QueryStringBindable, is added to easily pass a Resource to controller.
@412ff1984128f70a561d70ab69831d30dbffa7ec
--- app/controllers/AbstractPostingApp.java
+++ app/controllers/AbstractPostingApp.java
... | ... | @@ -151,7 +151,7 @@ |
151 | 151 |
notiEvent.senderId = UserApp.currentUser().id; |
152 | 152 |
notiEvent.receivers = watchers; |
153 | 153 |
notiEvent.urlToView = toView.absoluteURL(request()); |
154 |
- notiEvent.resourceId = comment.id; |
|
154 |
+ notiEvent.resourceId = comment.id.toString(); |
|
155 | 155 |
notiEvent.resourceType = comment.asResource().getType(); |
156 | 156 |
notiEvent.type = NotificationType.NEW_COMMENT; |
157 | 157 |
notiEvent.oldValue = null; |
... | ... | @@ -274,45 +274,5 @@ |
274 | 274 |
} |
275 | 275 |
|
276 | 276 |
return ok(content); |
277 |
- } |
|
278 |
- |
|
279 |
- /** |
|
280 |
- * 현재 사용자가 게시물을 명시적으로 지켜보는 것으로 설정한다. |
|
281 |
- * |
|
282 |
- * @param target |
|
283 |
- * @return |
|
284 |
- */ |
|
285 |
- public static Result watch(AbstractPosting target) { |
|
286 |
- User user = UserApp.currentUser(); |
|
287 |
- |
|
288 |
- if (!AccessControl.isAllowed(user, target.asResource(), Operation.READ)) { |
|
289 |
- return forbidden(ErrorViews.Forbidden.render("You have no permission to do that.", target.asResource().getProject())); |
|
290 |
- } |
|
291 |
- |
|
292 |
- if (user.isAnonymous()) { |
|
293 |
- return forbidden(ErrorViews.Forbidden.render("Anonymous cannot watch it.", target.asResource().getProject())); |
|
294 |
- } |
|
295 |
- |
|
296 |
- target.watch(user); |
|
297 |
- |
|
298 |
- return ok(); |
|
299 |
- } |
|
300 |
- |
|
301 |
- /** |
|
302 |
- * 현재 사용자가 게시물을 명시적으로 무시하는(지켜보지 않는) 것으로 설정한다. |
|
303 |
- * |
|
304 |
- * @param target |
|
305 |
- * @return |
|
306 |
- */ |
|
307 |
- public static Result unwatch(AbstractPosting target) { |
|
308 |
- User user = UserApp.currentUser(); |
|
309 |
- |
|
310 |
- if (user.isAnonymous()) { |
|
311 |
- return forbidden(ErrorViews.Forbidden.render("Anonymous cannot unwatch it.", target.asResource().getProject())); |
|
312 |
- } |
|
313 |
- |
|
314 |
- target.unwatch(user); |
|
315 |
- |
|
316 |
- return ok(); |
|
317 | 277 |
} |
318 | 278 |
} |
--- app/controllers/AttachmentApp.java
+++ app/controllers/AttachmentApp.java
... | ... | @@ -259,8 +259,8 @@ |
259 | 259 |
|
260 | 260 |
if (containerType != null && containerId != null) { |
261 | 261 |
List<Map<String, String>> attachments = new ArrayList<>(); |
262 |
- for (Attachment attach : Attachment.findByContainer(ResourceType.valueOf(containerType), |
|
263 |
- Long.parseLong(containerId))) { |
|
262 |
+ for (Attachment attach : Attachment.findByContainer(ResourceType.valueOf |
|
263 |
+ (containerType), containerId)) { |
|
264 | 264 |
if (!AccessControl.isAllowed(UserApp.currentUser(), |
265 | 265 |
attach.asResource(), Operation.READ)) { |
266 | 266 |
return forbidden(); |
--- app/controllers/BoardApp.java
+++ app/controllers/BoardApp.java
... | ... | @@ -160,7 +160,7 @@ |
160 | 160 |
notiEvent.senderId = UserApp.currentUser().id; |
161 | 161 |
notiEvent.receivers = watchers; |
162 | 162 |
notiEvent.urlToView = toPost.absoluteURL(request()); |
163 |
- notiEvent.resourceId = post.id; |
|
163 |
+ notiEvent.resourceId = post.id.toString(); |
|
164 | 164 |
notiEvent.resourceType = post.asResource().getType(); |
165 | 165 |
notiEvent.type = NotificationType.NEW_POSTING; |
166 | 166 |
notiEvent.oldValue = null; |
... | ... | @@ -367,20 +367,4 @@ |
367 | 367 |
|
368 | 368 |
return delete(comment, comment.asResource(), redirectTo); |
369 | 369 |
} |
370 |
- |
|
371 |
- public static Result watch(String ownerName, String projectName, Long postingNumber) { |
|
372 |
- Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
|
373 |
- Posting posting = Posting.findByNumber(project, postingNumber); |
|
374 |
- |
|
375 |
- return AbstractPostingApp.watch(posting); |
|
376 |
- } |
|
377 |
- |
|
378 |
- public static Result unwatch(String ownerName, String projectName, Long postingNumber) { |
|
379 |
- Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
|
380 |
- Posting posting = Posting.findByNumber(project, postingNumber); |
|
381 |
- |
|
382 |
- return AbstractPostingApp.unwatch(posting); |
|
383 |
- } |
|
384 |
- |
|
385 |
- |
|
386 | 370 |
} |
--- app/controllers/CodeHistoryApp.java
+++ app/controllers/CodeHistoryApp.java
... | ... | @@ -212,7 +212,7 @@ |
212 | 212 |
notiEvent.senderId = UserApp.currentUser().id; |
213 | 213 |
notiEvent.receivers = watchers; |
214 | 214 |
notiEvent.urlToView = toView.absoluteURL(request()); |
215 |
- notiEvent.resourceId = codeComment.id; |
|
215 |
+ notiEvent.resourceId = codeComment.id.toString(); |
|
216 | 216 |
notiEvent.resourceType = codeComment.asResource().getType(); |
217 | 217 |
notiEvent.type = NotificationType.NEW_COMMENT; |
218 | 218 |
notiEvent.oldValue = null; |
... | ... | @@ -237,42 +237,5 @@ |
237 | 237 |
codeComment.delete(); |
238 | 238 |
|
239 | 239 |
return redirect(routes.CodeHistoryApp.show(ownerName, projectName, commitId)); |
240 |
- } |
|
241 |
- |
|
242 |
- public static Result watch(String ownerName, String projectName, |
|
243 |
- String commitId) throws IOException, ServletException, SVNException { |
|
244 |
- Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
|
245 |
- Commit commit = RepositoryService.getRepository(project).getCommit(commitId); |
|
246 |
- |
|
247 |
- User user = UserApp.currentUser(); |
|
248 |
- |
|
249 |
- if (!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) { |
|
250 |
- return forbidden(ErrorViews.Forbidden.render("You have no permission to do that.", |
|
251 |
- project.asResource().getProject())); |
|
252 |
- } |
|
253 |
- |
|
254 |
- if (user.isAnonymous()) { |
|
255 |
- return forbidden(ErrorViews.Forbidden.render("Anonymous cannot watch it.", project)); |
|
256 |
- } |
|
257 |
- |
|
258 |
- commit.watch(project, user); |
|
259 |
- |
|
260 |
- return ok(); |
|
261 |
- } |
|
262 |
- |
|
263 |
- public static Result unwatch(String ownerName, String projectName, |
|
264 |
- String commitId) throws IOException, ServletException, SVNException { |
|
265 |
- Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
|
266 |
- Commit commit = RepositoryService.getRepository(project).getCommit(commitId); |
|
267 |
- |
|
268 |
- User user = UserApp.currentUser(); |
|
269 |
- |
|
270 |
- if (user.isAnonymous()) { |
|
271 |
- return forbidden(ErrorViews.Forbidden.render("Anonymous cannot unwatch it.", project)); |
|
272 |
- } |
|
273 |
- |
|
274 |
- commit.unwatch(project, user); |
|
275 |
- |
|
276 |
- return ok(); |
|
277 | 240 |
} |
278 | 241 |
} |
--- app/controllers/IssueApp.java
+++ app/controllers/IssueApp.java
... | ... | @@ -400,7 +400,7 @@ |
400 | 400 |
notiEvent.senderId = UserApp.currentUser().id; |
401 | 401 |
notiEvent.receivers = watchers; |
402 | 402 |
notiEvent.urlToView = issueCall.absoluteURL(request()); |
403 |
- notiEvent.resourceId = newIssue.id; |
|
403 |
+ notiEvent.resourceId = newIssue.id.toString(); |
|
404 | 404 |
notiEvent.resourceType = newIssue.asResource().getType(); |
405 | 405 |
notiEvent.type = NotificationType.NEW_ISSUE; |
406 | 406 |
notiEvent.oldValue = null; |
... | ... | @@ -554,7 +554,7 @@ |
554 | 554 |
|
555 | 555 |
notiEvent.created = new Date(); |
556 | 556 |
notiEvent.urlToView = urlToView; |
557 |
- notiEvent.resourceId = updatedIssue.id; |
|
557 |
+ notiEvent.resourceId = updatedIssue.id.toString(); |
|
558 | 558 |
notiEvent.resourceType = updatedIssue.asResource().getType(); |
559 | 559 |
notiEvent.type = NotificationType.ISSUE_STATE_CHANGED; |
560 | 560 |
|
... | ... | @@ -591,7 +591,7 @@ |
591 | 591 |
notiEvent.senderId = UserApp.currentUser().id; |
592 | 592 |
notiEvent.receivers = receivers; |
593 | 593 |
notiEvent.urlToView = urlToView; |
594 |
- notiEvent.resourceId = updatedIssue.id; |
|
594 |
+ notiEvent.resourceId = updatedIssue.id.toString(); |
|
595 | 595 |
notiEvent.resourceType = updatedIssue.asResource().getType(); |
596 | 596 |
notiEvent.type = NotificationType.ISSUE_ASSIGNEE_CHANGED; |
597 | 597 |
|
... | ... | @@ -728,19 +728,5 @@ |
728 | 728 |
labels.add(IssueLabel.finder.byId(Long.parseLong(labelId))); |
729 | 729 |
} |
730 | 730 |
} |
731 |
- } |
|
732 |
- |
|
733 |
- public static Result watch(String ownerName, String projectName, Long issueNumber) { |
|
734 |
- Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
|
735 |
- Issue issue = Issue.findByNumber(project, issueNumber); |
|
736 |
- |
|
737 |
- return AbstractPostingApp.watch(issue); |
|
738 |
- } |
|
739 |
- |
|
740 |
- public static Result unwatch(String ownerName, String projectName, Long issueNumber) { |
|
741 |
- Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
|
742 |
- Issue issue = Issue.findByNumber(project, issueNumber); |
|
743 |
- |
|
744 |
- return AbstractPostingApp.unwatch(issue); |
|
745 | 731 |
} |
746 | 732 |
} |
--- app/controllers/UserApp.java
+++ app/controllers/UserApp.java
... | ... | @@ -418,7 +418,7 @@ |
418 | 418 |
addProjectNotDupped(projectCollection, Project.findProjectsJustMemberAndNotOwner(user)); |
419 | 419 |
break; |
420 | 420 |
case "watching": |
421 |
- addProjectNotDupped(projectCollection, user.watchingProjects); |
|
421 |
+ addProjectNotDupped(projectCollection, user.getWatchingProjects()); |
|
422 | 422 |
break; |
423 | 423 |
} |
424 | 424 |
} |
+++ app/controllers/WatchApp.java
... | ... | @@ -0,0 +1,46 @@ |
1 | +package controllers; | |
2 | + | |
3 | +import models.User; | |
4 | +import models.enumeration.Operation; | |
5 | +import models.resource.Resource; | |
6 | +import models.resource.ResourceParam; | |
7 | +import play.mvc.Controller; | |
8 | +import play.mvc.Result; | |
9 | +import utils.AccessControl; | |
10 | +import utils.WatchService; | |
11 | + | |
12 | +public class WatchApp extends Controller { | |
13 | + public static Result watch(ResourceParam resourceParam) { | |
14 | + User user = UserApp.currentUser(); | |
15 | + Resource resource = resourceParam.resource; | |
16 | + | |
17 | + if (user.isAnonymous()) { | |
18 | + return forbidden("Anonymous cannot watch it."); | |
19 | + } | |
20 | + | |
21 | + if (resource == null) { | |
22 | + return notFound(); | |
23 | + } | |
24 | + | |
25 | + if (!AccessControl.isAllowed(user, resource, Operation.READ)) { | |
26 | + return forbidden("You have no permission to watch it."); | |
27 | + } | |
28 | + | |
29 | + WatchService.watch(user, resource); | |
30 | + | |
31 | + return ok(); | |
32 | + } | |
33 | + | |
34 | + public static Result unwatch(ResourceParam resourceParam) { | |
35 | + User user = UserApp.currentUser(); | |
36 | + Resource resource = resourceParam.resource; | |
37 | + | |
38 | + if (user.isAnonymous()) { | |
39 | + return forbidden("Anonymous cannot unwatch it."); | |
40 | + } | |
41 | + | |
42 | + WatchService.unwatch(user, resource); | |
43 | + | |
44 | + return ok(); | |
45 | + } | |
46 | +} |
--- app/controllers/WatchProjectApp.java
+++ app/controllers/WatchProjectApp.java
... | ... | @@ -7,6 +7,7 @@ |
7 | 7 |
import play.mvc.Result; |
8 | 8 |
import utils.Constants; |
9 | 9 |
import utils.ErrorViews; |
10 |
+import utils.WatchService; |
|
10 | 11 |
|
11 | 12 |
public class WatchProjectApp extends Controller { |
12 | 13 |
|
... | ... | @@ -22,8 +23,7 @@ |
22 | 23 |
return redirect(routes.UserApp.loginForm()); |
23 | 24 |
} |
24 | 25 |
|
25 |
- user.addWatching(project); |
|
26 |
- |
|
26 |
+ WatchService.watch(project.asResource()); |
|
27 | 27 |
|
28 | 28 |
return redirect(request().getHeader(Http.HeaderNames.REFERER)); |
29 | 29 |
} |
... | ... | @@ -40,7 +40,7 @@ |
40 | 40 |
return redirect(routes.UserApp.loginForm()); |
41 | 41 |
} |
42 | 42 |
|
43 |
- user.removeWatching(project); |
|
43 |
+ WatchService.unwatch(project.asResource()); |
|
44 | 44 |
|
45 | 45 |
return redirect(request().getHeader(Http.HeaderNames.REFERER)); |
46 | 46 |
} |
... | ... | @@ -48,4 +48,4 @@ |
48 | 48 |
private static Result badProject(String userName, String projectName) { |
49 | 49 |
return badRequest(ErrorViews.BadRequest.render("No project matches given user name '" + userName + "' and project name '" + projectName + "'")); |
50 | 50 |
} |
51 |
-} |
|
51 |
+}(No newline at end of file) |
--- app/models/AbstractPosting.java
+++ app/models/AbstractPosting.java
... | ... | @@ -6,16 +6,15 @@ |
6 | 6 |
import models.enumeration.ResourceType; |
7 | 7 |
import models.resource.Resource; |
8 | 8 |
import org.joda.time.Duration; |
9 |
-import play.Logger; |
|
10 | 9 |
import play.data.format.Formats; |
11 | 10 |
import play.data.validation.Constraints; |
12 | 11 |
import play.db.ebean.*; |
13 | 12 |
import utils.AccessControl; |
14 | 13 |
import utils.JodaDateUtil; |
14 |
+import utils.WatchService; |
|
15 | 15 |
|
16 | 16 |
import javax.persistence.*; |
17 | 17 |
import javax.validation.constraints.Size; |
18 |
-import javax.xml.stream.util.XMLEventConsumer; |
|
19 | 18 |
import java.util.Date; |
20 | 19 |
import java.util.HashSet; |
21 | 20 |
import java.util.List; |
... | ... | @@ -62,10 +61,6 @@ |
62 | 61 |
// This field is only for ordering. This field should be persistent because |
63 | 62 |
// Ebean does NOT sort entities by transient field. |
64 | 63 |
public int numOfComments; |
65 |
- |
|
66 |
- abstract protected Set<User> getExplicitWatchers(); |
|
67 |
- |
|
68 |
- abstract protected Set<User> getExplicitUnwatchers(); |
|
69 | 64 |
|
70 | 65 |
/** |
71 | 66 |
* {@link Comment} 개수를 반환한다. |
... | ... | @@ -177,8 +172,8 @@ |
177 | 172 |
public Resource asResource(final ResourceType type) { |
178 | 173 |
return new Resource() { |
179 | 174 |
@Override |
180 |
- public Long getId() { |
|
181 |
- return id; |
|
175 |
+ public String getId() { |
|
176 |
+ return id.toString(); |
|
182 | 177 |
} |
183 | 178 |
|
184 | 179 |
@Override |
... | ... | @@ -279,11 +274,9 @@ |
279 | 274 |
} |
280 | 275 |
} |
281 | 276 |
|
282 |
- List<User> watchers = project.watchers; |
|
283 |
- actualWatchers.addAll(watchers); |
|
284 |
- |
|
285 |
- actualWatchers.addAll(getExplicitWatchers()); |
|
286 |
- actualWatchers.removeAll(getExplicitUnwatchers()); |
|
277 |
+ actualWatchers.addAll(WatchService.findWatchers(project.asResource())); |
|
278 |
+ actualWatchers.addAll(WatchService.findWatchers(asResource())); |
|
279 |
+ actualWatchers.removeAll(WatchService.findUnwatchers(asResource())); |
|
287 | 280 |
|
288 | 281 |
Set<User> allowedWatchers = new HashSet<>(); |
289 | 282 |
for (User watcher : actualWatchers) { |
... | ... | @@ -293,29 +286,5 @@ |
293 | 286 |
} |
294 | 287 |
|
295 | 288 |
return allowedWatchers; |
296 |
- } |
|
297 |
- |
|
298 |
- /** |
|
299 |
- * {@code user}가 명시적으로 이 게시물을 지켜보는 것으로 설정한다. |
|
300 |
- * |
|
301 |
- * @param user |
|
302 |
- */ |
|
303 |
- @Transactional |
|
304 |
- public void watch(User user) { |
|
305 |
- getExplicitWatchers().add(user); |
|
306 |
- getExplicitUnwatchers().remove(user); |
|
307 |
- update(); |
|
308 |
- } |
|
309 |
- |
|
310 |
- /** |
|
311 |
- * {@code user}가 명시적으로 이 게시물을 무시하는 것(지켜보지 않는 것)으로 설정한다. |
|
312 |
- * |
|
313 |
- * @param user |
|
314 |
- */ |
|
315 |
- @Transactional |
|
316 |
- public void unwatch(User user) { |
|
317 |
- getExplicitUnwatchers().add(user); |
|
318 |
- getExplicitWatchers().remove(user); |
|
319 |
- update(); |
|
320 | 289 |
} |
321 | 290 |
} |
--- app/models/Attachment.java
+++ app/models/Attachment.java
... | ... | @@ -46,7 +46,7 @@ |
46 | 46 |
|
47 | 47 |
public Long size; |
48 | 48 |
|
49 |
- public Long containerId; |
|
49 |
+ public String containerId; |
|
50 | 50 |
|
51 | 51 |
/** |
52 | 52 |
* 주어진 {@code attach}와 내용이 같은 첨부 파일을 찾는다. |
... | ... | @@ -87,7 +87,7 @@ |
87 | 87 |
* @return 첨부 파일의 목록 |
88 | 88 |
*/ |
89 | 89 |
public static List<Attachment> findByContainer( |
90 |
- ResourceType containerType, Long containerId) { |
|
90 |
+ ResourceType containerType, String containerId) { |
|
91 | 91 |
return find.where() |
92 | 92 |
.eq("containerType", containerType) |
93 | 93 |
.eq("containerId", containerId).findList(); |
... | ... | @@ -324,8 +324,8 @@ |
324 | 324 |
public Resource asResource() { |
325 | 325 |
return new Resource() { |
326 | 326 |
@Override |
327 |
- public Long getId() { |
|
328 |
- return id; |
|
327 |
+ public String getId() { |
|
328 |
+ return id.toString(); |
|
329 | 329 |
} |
330 | 330 |
|
331 | 331 |
@Override |
... | ... | @@ -347,7 +347,7 @@ |
347 | 347 |
return new Resource() { |
348 | 348 |
|
349 | 349 |
@Override |
350 |
- public Long getId() { |
|
350 |
+ public String getId() { |
|
351 | 351 |
return containerId; |
352 | 352 |
} |
353 | 353 |
|
--- app/models/CodeComment.java
+++ app/models/CodeComment.java
... | ... | @@ -57,8 +57,8 @@ |
57 | 57 |
public Resource asResource() { |
58 | 58 |
return new Resource() { |
59 | 59 |
@Override |
60 |
- public Long getId() { |
|
61 |
- return id; |
|
60 |
+ public String getId() { |
|
61 |
+ return id.toString(); |
|
62 | 62 |
} |
63 | 63 |
|
64 | 64 |
@Override |
--- app/models/CommitExplicitWatching.java
... | ... | @@ -1,57 +0,0 @@ |
1 | -package models; | |
2 | - | |
3 | -import com.avaje.ebean.validation.NotNull; | |
4 | -import controllers.CodeHistoryApp; | |
5 | -import play.db.ebean.Model; | |
6 | - | |
7 | -import javax.persistence.*; | |
8 | -import java.util.Set; | |
9 | - | |
10 | -@Entity | |
11 | -public class CommitExplicitWatching extends Model { | |
12 | - private static final long serialVersionUID = 1L; | |
13 | - | |
14 | - @Id | |
15 | - public Long id; | |
16 | - | |
17 | - @ManyToOne | |
18 | - public Project project; | |
19 | - | |
20 | - @NotNull | |
21 | - public String commitId; | |
22 | - | |
23 | - @ManyToMany | |
24 | - @JoinTable(name="commit_explicit_watcher") | |
25 | - public Set<User> watchers; | |
26 | - | |
27 | - @ManyToMany | |
28 | - @JoinTable(name="commit_explicit_unwatcher") | |
29 | - public Set<User> unwatchers; | |
30 | - | |
31 | - public static Finder<Long, CommitExplicitWatching> find = new Finder<>(Long.class, | |
32 | - CommitExplicitWatching.class); | |
33 | - | |
34 | - public static CommitExplicitWatching getOrCreate(Project project, String commitId) { | |
35 | - CommitExplicitWatching watching = findByProjectAndCommitId(project, commitId); | |
36 | - | |
37 | - if (watching == null) { | |
38 | - watching = create(project, commitId); | |
39 | - } | |
40 | - | |
41 | - return watching; | |
42 | - } | |
43 | - | |
44 | - public static CommitExplicitWatching create(Project project, String commitId) { | |
45 | - CommitExplicitWatching watching = new CommitExplicitWatching(); | |
46 | - watching.commitId = commitId; | |
47 | - watching.project = project; | |
48 | - watching.save(); | |
49 | - | |
50 | - return watching; | |
51 | - } | |
52 | - | |
53 | - public static CommitExplicitWatching findByProjectAndCommitId(Project project, | |
54 | - String commitId) { | |
55 | - return find.where().eq("project.id", project.id).eq("commitId", commitId).findUnique(); | |
56 | - } | |
57 | -} |
--- app/models/Issue.java
+++ app/models/Issue.java
... | ... | @@ -287,8 +287,8 @@ |
287 | 287 |
public Resource fieldAsResource(final ResourceType resourceType) { |
288 | 288 |
return new Resource() { |
289 | 289 |
@Override |
290 |
- public Long getId() { |
|
291 |
- return id; |
|
290 |
+ public String getId() { |
|
291 |
+ return id.toString(); |
|
292 | 292 |
} |
293 | 293 |
|
294 | 294 |
@Override |
... | ... | @@ -359,28 +359,6 @@ |
359 | 359 |
return super.getWatchers(baseWatchers); |
360 | 360 |
} |
361 | 361 |
|
362 |
- /** |
|
363 |
- * 명시적으로 이 이슈를 지켜보고 있는 사용자들 |
|
364 |
- */ |
|
365 |
- @ManyToMany |
|
366 |
- @JoinTable(name="ISSUE_EXPLICIT_WATCHER") |
|
367 |
- private Set<User> explicitWatchers; |
|
368 |
- |
|
369 |
- /** |
|
370 |
- * 명시적으로 이 이슈를 무시하는(지켜보지 않는) 사용자들 |
|
371 |
- */ |
|
372 |
- @ManyToMany |
|
373 |
- @JoinTable(name="ISSUE_EXPLICIT_UNWATCHER") |
|
374 |
- private Set<User> explicitUnwatchers; |
|
375 |
- |
|
376 |
- |
|
377 |
- protected Set<User> getExplicitWatchers() { |
|
378 |
- return explicitWatchers; |
|
379 |
- } |
|
380 |
- |
|
381 |
- protected Set<User> getExplicitUnwatchers() { |
|
382 |
- return explicitUnwatchers; |
|
383 |
- } |
|
384 | 362 |
|
385 | 363 |
public boolean assigneeEquals(Assignee otherAssignee) { |
386 | 364 |
return (assignee == otherAssignee) || |
--- app/models/IssueComment.java
+++ app/models/IssueComment.java
... | ... | @@ -29,8 +29,8 @@ |
29 | 29 |
public Resource asResource() { |
30 | 30 |
return new Resource() { |
31 | 31 |
@Override |
32 |
- public Long getId() { |
|
33 |
- return id; |
|
32 |
+ public String getId() { |
|
33 |
+ return id.toString(); |
|
34 | 34 |
} |
35 | 35 |
|
36 | 36 |
@Override |
--- app/models/IssueLabel.java
+++ app/models/IssueLabel.java
... | ... | @@ -72,8 +72,8 @@ |
72 | 72 |
public Resource asResource() { |
73 | 73 |
return new Resource() { |
74 | 74 |
@Override |
75 |
- public Long getId() { |
|
76 |
- return id; |
|
75 |
+ public String getId() { |
|
76 |
+ return id.toString(); |
|
77 | 77 |
} |
78 | 78 |
|
79 | 79 |
@Override |
... | ... | @@ -87,4 +87,4 @@ |
87 | 87 |
} |
88 | 88 |
}; |
89 | 89 |
} |
90 |
-}(No newline at end of file) |
|
90 |
+} |
--- app/models/Label.java
+++ app/models/Label.java
... | ... | @@ -98,8 +98,8 @@ |
98 | 98 |
public Resource asResource() { |
99 | 99 |
return new Resource() { |
100 | 100 |
@Override |
101 |
- public Long getId() { |
|
102 |
- return id; |
|
101 |
+ public String getId() { |
|
102 |
+ return id.toString(); |
|
103 | 103 |
} |
104 | 104 |
|
105 | 105 |
@Override |
--- app/models/Milestone.java
+++ app/models/Milestone.java
... | ... | @@ -254,8 +254,8 @@ |
254 | 254 |
public Resource asResource() { |
255 | 255 |
return new Resource() { |
256 | 256 |
@Override |
257 |
- public Long getId() { |
|
258 |
- return id; |
|
257 |
+ public String getId() { |
|
258 |
+ return id.toString(); |
|
259 | 259 |
} |
260 | 260 |
|
261 | 261 |
@Override |
--- app/models/NotificationEvent.java
+++ app/models/NotificationEvent.java
... | ... | @@ -12,7 +12,6 @@ |
12 | 12 |
|
13 | 13 |
import javax.persistence.*; |
14 | 14 |
import java.util.Date; |
15 |
-import java.util.EnumSet; |
|
16 | 15 |
import java.util.HashSet; |
17 | 16 |
import java.util.Set; |
18 | 17 |
import java.util.regex.Matcher; |
... | ... | @@ -49,7 +48,7 @@ |
49 | 48 |
@Enumerated(EnumType.STRING) |
50 | 49 |
public ResourceType resourceType; |
51 | 50 |
|
52 |
- public Long resourceId; |
|
51 |
+ public String resourceId; |
|
53 | 52 |
|
54 | 53 |
@Enumerated(EnumType.STRING) |
55 | 54 |
public NotificationType type; |
... | ... | @@ -124,60 +123,15 @@ |
124 | 123 |
public User getSender() { |
125 | 124 |
return User.find.byId(this.senderId); |
126 | 125 |
} |
127 |
- |
|
126 |
+ |
|
128 | 127 |
public Resource getResource() { |
129 |
- Resource resource = null; |
|
130 |
- |
|
131 |
- switch(resourceType) { |
|
132 |
- case ISSUE_POST: |
|
133 |
- resource = Issue.finder.byId(resourceId).asResource(); |
|
134 |
- break; |
|
135 |
- case ISSUE_COMMENT: |
|
136 |
- resource = IssueComment.find.byId(resourceId).asResource(); |
|
137 |
- break; |
|
138 |
- case NONISSUE_COMMENT: |
|
139 |
- resource = PostingComment.find.byId(resourceId).asResource(); |
|
140 |
- break; |
|
141 |
- case LABEL: |
|
142 |
- resource = Label.find.byId(resourceId).asResource(); |
|
143 |
- break; |
|
144 |
- case BOARD_POST: |
|
145 |
- resource = Posting.finder.byId(resourceId).asResource(); |
|
146 |
- break; |
|
147 |
- case USER: |
|
148 |
- resource = null; |
|
149 |
- break; |
|
150 |
- case PROJECT: |
|
151 |
- resource = Project.find.byId(resourceId).asResource(); |
|
152 |
- break; |
|
153 |
- case ATTACHMENT: |
|
154 |
- resource = Attachment.find.byId(resourceId).asResource(); |
|
155 |
- break; |
|
156 |
- case MILESTONE: |
|
157 |
- resource = Milestone.find.byId(resourceId).asResource(); |
|
158 |
- break; |
|
159 |
- case CODE_COMMENT: |
|
160 |
- resource = CodeComment.find.byId(resourceId).asResource(); |
|
161 |
- break; |
|
162 |
- default: |
|
163 |
- throw new IllegalArgumentException(getInvalidResourceTypeMessage(resourceType)); |
|
164 |
- } |
|
165 |
- |
|
166 |
- return resource; |
|
167 |
- } |
|
168 |
- |
|
169 |
- private static String getInvalidResourceTypeMessage(ResourceType resourceType) { |
|
170 |
- if (EnumSet.allOf(ResourceType.class).contains(resourceType)) { |
|
171 |
- return "Unsupported resource type " + resourceType; |
|
172 |
- } else { |
|
173 |
- return "Unknown resource type " + resourceType; |
|
174 |
- } |
|
128 |
+ return Resource.get(resourceType, resourceId); |
|
175 | 129 |
} |
176 | 130 |
|
177 | 131 |
public Project getProject() { |
178 | 132 |
switch(resourceType) { |
179 | 133 |
case ISSUE_ASSIGNEE: |
180 |
- return Assignee.finder.byId(resourceId).project; |
|
134 |
+ return Assignee.finder.byId(Long.valueOf(resourceId)).project; |
|
181 | 135 |
default: |
182 | 136 |
Resource resource = getResource(); |
183 | 137 |
if (resource != null) { |
... | ... | @@ -189,47 +143,7 @@ |
189 | 143 |
} |
190 | 144 |
|
191 | 145 |
public boolean resourceExists() { |
192 |
- Finder<Long, ? extends Model> finder = null; |
|
193 |
- |
|
194 |
- switch(resourceType) { |
|
195 |
- case ISSUE_POST: |
|
196 |
- finder = Issue.finder; |
|
197 |
- break; |
|
198 |
- case ISSUE_ASSIGNEE: |
|
199 |
- finder = Assignee.finder; |
|
200 |
- break; |
|
201 |
- case ISSUE_COMMENT: |
|
202 |
- finder = IssueComment.find; |
|
203 |
- break; |
|
204 |
- case NONISSUE_COMMENT: |
|
205 |
- finder = PostingComment.find; |
|
206 |
- break; |
|
207 |
- case LABEL: |
|
208 |
- finder = Label.find; |
|
209 |
- break; |
|
210 |
- case BOARD_POST: |
|
211 |
- finder = Posting.finder; |
|
212 |
- break; |
|
213 |
- case USER: |
|
214 |
- finder = User.find; |
|
215 |
- break; |
|
216 |
- case PROJECT: |
|
217 |
- finder = Project.find; |
|
218 |
- break; |
|
219 |
- case ATTACHMENT: |
|
220 |
- finder = Attachment.find; |
|
221 |
- break; |
|
222 |
- case MILESTONE: |
|
223 |
- finder = Milestone.find; |
|
224 |
- break; |
|
225 |
- case CODE_COMMENT: |
|
226 |
- finder = CodeComment.find; |
|
227 |
- break; |
|
228 |
- default: |
|
229 |
- throw new IllegalArgumentException(getInvalidResourceTypeMessage(resourceType)); |
|
230 |
- } |
|
231 |
- |
|
232 |
- return finder.byId(resourceId) != null; |
|
146 |
+ return Resource.exists(resourceType, resourceId); |
|
233 | 147 |
} |
234 | 148 |
|
235 | 149 |
public static void add(NotificationEvent event) { |
--- app/models/NullUser.java
+++ app/models/NullUser.java
... | ... | @@ -32,8 +32,8 @@ |
32 | 32 |
public Resource asResource() { |
33 | 33 |
return new Resource() { |
34 | 34 |
@Override |
35 |
- public Long getId() { |
|
36 |
- return id; |
|
35 |
+ public String getId() { |
|
36 |
+ return id.toString(); |
|
37 | 37 |
} |
38 | 38 |
|
39 | 39 |
@Override |
--- app/models/Posting.java
+++ app/models/Posting.java
... | ... | @@ -138,26 +138,4 @@ |
138 | 138 |
public static int countPostings(Project project) { |
139 | 139 |
return finder.where().eq("project", project).findRowCount(); |
140 | 140 |
} |
141 |
- |
|
142 |
- /** |
|
143 |
- * 명시적으로 이 게시물을 지켜보고 있는 사용자들 |
|
144 |
- */ |
|
145 |
- @ManyToMany |
|
146 |
- @JoinTable(name="POSTING_EXPLICIT_WATCHER") |
|
147 |
- private Set<User> explicitWatchers; |
|
148 |
- |
|
149 |
- /** |
|
150 |
- * 명시적으로 이 게시물을 무시하는(지켜보지 않는) 사용자들 |
|
151 |
- */ |
|
152 |
- @ManyToMany |
|
153 |
- @JoinTable(name="POSTING_EXPLICIT_UNWATCHER") |
|
154 |
- private Set<User> explicitUnwatchers; |
|
155 |
- |
|
156 |
- protected Set<User> getExplicitWatchers() { |
|
157 |
- return explicitWatchers; |
|
158 |
- } |
|
159 |
- |
|
160 |
- protected Set<User> getExplicitUnwatchers() { |
|
161 |
- return explicitUnwatchers; |
|
162 |
- } |
|
163 | 141 |
} |
--- app/models/PostingComment.java
+++ app/models/PostingComment.java
... | ... | @@ -29,8 +29,8 @@ |
29 | 29 |
public Resource asResource() { |
30 | 30 |
return new Resource() { |
31 | 31 |
@Override |
32 |
- public Long getId() { |
|
33 |
- return id; |
|
32 |
+ public String getId() { |
|
33 |
+ return id.toString(); |
|
34 | 34 |
} |
35 | 35 |
|
36 | 36 |
@Override |
--- app/models/Project.java
+++ app/models/Project.java
... | ... | @@ -98,13 +98,6 @@ |
98 | 98 |
@ManyToMany(mappedBy = "enrolledProjects") |
99 | 99 |
public List<User> enrolledUsers; |
100 | 100 |
|
101 |
- @ManyToMany |
|
102 |
- @JoinTable(name = "user_watching_project", |
|
103 |
- joinColumns= @JoinColumn(name="project_id"), |
|
104 |
- inverseJoinColumns= @JoinColumn(name="user_id") |
|
105 |
- ) |
|
106 |
- public List<User> watchers; |
|
107 |
- |
|
108 | 101 |
/** |
109 | 102 |
* 신규 프로젝트를 생성한다. |
110 | 103 |
* |
... | ... | @@ -443,8 +436,8 @@ |
443 | 436 |
return new Resource() { |
444 | 437 |
|
445 | 438 |
@Override |
446 |
- public Long getId() { |
|
447 |
- return id; |
|
439 |
+ public String getId() { |
|
440 |
+ return id.toString(); |
|
448 | 441 |
} |
449 | 442 |
|
450 | 443 |
@Override |
... | ... | @@ -469,8 +462,8 @@ |
469 | 462 |
return new Resource() { |
470 | 463 |
|
471 | 464 |
@Override |
472 |
- public Long getId() { |
|
473 |
- return id; |
|
465 |
+ public String getId() { |
|
466 |
+ return id.toString(); |
|
474 | 467 |
} |
475 | 468 |
|
476 | 469 |
@Override |
--- app/models/PullRequest.java
+++ app/models/PullRequest.java
... | ... | @@ -216,8 +216,8 @@ |
216 | 216 |
public Resource asResource() { |
217 | 217 |
return new Resource() { |
218 | 218 |
@Override |
219 |
- public Long getId() { |
|
220 |
- return id; |
|
219 |
+ public String getId() { |
|
220 |
+ return id.toString(); |
|
221 | 221 |
} |
222 | 222 |
|
223 | 223 |
@Override |
--- app/models/SimpleComment.java
+++ app/models/SimpleComment.java
... | ... | @@ -79,8 +79,8 @@ |
79 | 79 |
public Resource asResource(){ |
80 | 80 |
return new Resource() { |
81 | 81 |
@Override |
82 |
- public Long getId() { |
|
83 |
- return id; |
|
82 |
+ public String getId() { |
|
83 |
+ return id.toString(); |
|
84 | 84 |
} |
85 | 85 |
|
86 | 86 |
@Override |
+++ app/models/Unwatch.java
... | ... | @@ -0,0 +1,25 @@ |
1 | +package models; | |
2 | + | |
3 | +import models.enumeration.ResourceType; | |
4 | + | |
5 | +import javax.persistence.*; | |
6 | +import java.util.List; | |
7 | + | |
8 | +@Entity | |
9 | +public class Unwatch extends UserAction { | |
10 | + private static final long serialVersionUID = 1L; | |
11 | + | |
12 | + public static Finder<Long, Unwatch> find = new Finder<>(Long.class, Unwatch.class); | |
13 | + | |
14 | + public static List<Unwatch> findBy(ResourceType resourceType, String resourceId) { | |
15 | + return findBy(find, resourceType, resourceId); | |
16 | + } | |
17 | + | |
18 | + public static Unwatch findBy(User watcher, ResourceType resourceType, String resourceId) { | |
19 | + return findBy(find, watcher, resourceType, resourceId); | |
20 | + } | |
21 | + | |
22 | + public static List<Unwatch> findBy(User user, ResourceType resourceType) { | |
23 | + return findBy(find, user, resourceType); | |
24 | + } | |
25 | +} |
--- app/models/User.java
+++ app/models/User.java
... | ... | @@ -24,6 +24,7 @@ |
24 | 24 |
import utils.ReservedWordsValidator; |
25 | 25 |
|
26 | 26 |
import com.avaje.ebean.Page; |
27 |
+import utils.WatchService; |
|
27 | 28 |
|
28 | 29 |
/** |
29 | 30 |
* User 클래스 |
... | ... | @@ -112,16 +113,6 @@ |
112 | 113 |
*/ |
113 | 114 |
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL) |
114 | 115 |
public List<ProjectUser> projectUser; |
115 |
- |
|
116 |
- /** |
|
117 |
- * 관심 프로젝트 |
|
118 |
- */ |
|
119 |
- @ManyToMany |
|
120 |
- @JoinTable(name = "user_watching_project", |
|
121 |
- joinColumns= @JoinColumn(name="user_id"), |
|
122 |
- inverseJoinColumns= @JoinColumn(name="project_id") |
|
123 |
- ) |
|
124 |
- public List<Project> watchingProjects; |
|
125 | 116 |
|
126 | 117 |
/** |
127 | 118 |
* 멤버 등록 요청한 프로젝트 |
... | ... | @@ -324,8 +315,8 @@ |
324 | 315 |
public Resource asResource() { |
325 | 316 |
return new Resource() { |
326 | 317 |
@Override |
327 |
- public Long getId() { |
|
328 |
- return id; |
|
318 |
+ public String getId() { |
|
319 |
+ return id.toString(); |
|
329 | 320 |
} |
330 | 321 |
|
331 | 322 |
@Override |
... | ... | @@ -343,8 +334,8 @@ |
343 | 334 |
public Resource avatarAsResource() { |
344 | 335 |
return new Resource() { |
345 | 336 |
@Override |
346 |
- public Long getId() { |
|
347 |
- return id; |
|
337 |
+ public String getId() { |
|
338 |
+ return id.toString(); |
|
348 | 339 |
} |
349 | 340 |
|
350 | 341 |
@Override |
... | ... | @@ -367,13 +358,6 @@ |
367 | 358 |
return SiteAdmin.exists(this); |
368 | 359 |
} |
369 | 360 |
|
370 |
- public List<Project> getWatchingProjects(){ |
|
371 |
- if(this.watchingProjects == null) { |
|
372 |
- this.watchingProjects = new ArrayList<>(); |
|
373 |
- } |
|
374 |
- return this.watchingProjects; |
|
375 |
- } |
|
376 |
- |
|
377 | 361 |
public List<Project> getEnrolledProjects(){ |
378 | 362 |
if(this.enrolledProjects == null) { |
379 | 363 |
this.enrolledProjects = new ArrayList<>(); |
... | ... | @@ -383,28 +367,29 @@ |
383 | 367 |
|
384 | 368 |
@Transactional |
385 | 369 |
public void addWatching(Project project) { |
386 |
- getWatchingProjects().add(project); |
|
387 |
- update(); |
|
388 |
- |
|
370 |
+ WatchService.watch(this, project.asResource()); |
|
389 | 371 |
project.upWatcingCount(); |
390 | 372 |
project.update(); |
391 | 373 |
} |
392 | 374 |
|
393 | 375 |
@Transactional |
394 | 376 |
public void removeWatching(Project project) { |
395 |
- getWatchingProjects().remove(project); |
|
396 |
- update(); |
|
397 |
- |
|
377 |
+ WatchService.unwatch(this, project.asResource()); |
|
398 | 378 |
project.downWathcingCount(); |
399 | 379 |
project.update(); |
400 | 380 |
} |
401 | 381 |
|
402 | 382 |
public static boolean isWatching(Project project) { |
403 |
- User user = UserApp.currentUser(); |
|
404 |
- if(user.isAnonymous()) { |
|
405 |
- return false; |
|
383 |
+ return WatchService.isWatching(project.asResource()); |
|
384 |
+ } |
|
385 |
+ |
|
386 |
+ public List<Project> getWatchingProjects() { |
|
387 |
+ List<String> projectIds = WatchService.findWatchedResourceIds(this, ResourceType.PROJECT); |
|
388 |
+ List<Project> projects = new ArrayList<>(); |
|
389 |
+ for (String id : projectIds) { |
|
390 |
+ projects.add(Project.find.byId(Long.valueOf(id))); |
|
406 | 391 |
} |
407 |
- return user.getWatchingProjects().contains(project); |
|
392 |
+ return projects; |
|
408 | 393 |
} |
409 | 394 |
|
410 | 395 |
/** |
+++ app/models/UserAction.java
... | ... | @@ -0,0 +1,43 @@ |
1 | +package models; | |
2 | + | |
3 | +import models.enumeration.ResourceType; | |
4 | +import play.db.ebean.Model; | |
5 | + | |
6 | +import javax.persistence.*; | |
7 | +import java.util.List; | |
8 | + | |
9 | +@MappedSuperclass | |
10 | +abstract public class UserAction extends Model { | |
11 | + @Id | |
12 | + public Long id; | |
13 | + | |
14 | + @ManyToOne | |
15 | + public User user; | |
16 | + | |
17 | + @Enumerated(EnumType.STRING) | |
18 | + public models.enumeration.ResourceType resourceType; | |
19 | + | |
20 | + public String resourceId; | |
21 | + | |
22 | + public static <T extends UserAction> List<T> findBy(Finder<Long, T> finder, | |
23 | + ResourceType resourceType, String resourceId) { | |
24 | + return finder.where() | |
25 | + .eq("resourceType", resourceType) | |
26 | + .eq("resourceId", resourceId).findList(); | |
27 | + } | |
28 | + | |
29 | + public static <T extends UserAction> T findBy(Finder<Long, T> finder, User subject, | |
30 | + ResourceType resourceType, String resourceId) { | |
31 | + return finder.where() | |
32 | + .eq("user.id", subject.id) | |
33 | + .eq("resourceType", resourceType) | |
34 | + .eq("resourceId", resourceId).findUnique(); | |
35 | + } | |
36 | + | |
37 | + public static <T extends UserAction> List<T> findBy(Finder<Long, T> finder, User subject, | |
38 | + ResourceType resourceType) { | |
39 | + return finder.where() | |
40 | + .eq("user.id", subject.id) | |
41 | + .eq("resourceType", resourceType).findList(); | |
42 | + } | |
43 | +} |
+++ app/models/Watch.java
... | ... | @@ -0,0 +1,25 @@ |
1 | +package models; | |
2 | + | |
3 | +import models.enumeration.ResourceType; | |
4 | + | |
5 | +import javax.persistence.*; | |
6 | +import java.util.List; | |
7 | + | |
8 | +@Entity | |
9 | +public class Watch extends UserAction { | |
10 | + private static final long serialVersionUID = 1L; | |
11 | + | |
12 | + public static Finder<Long, Watch> find = new Finder<>(Long.class, Watch.class); | |
13 | + | |
14 | + public static List<Watch> findBy(ResourceType resourceType, String resourceId) { | |
15 | + return findBy(find, resourceType, resourceId); | |
16 | + } | |
17 | + | |
18 | + public static Watch findBy(User watcher, ResourceType resourceType, String resourceId) { | |
19 | + return findBy(find, watcher, resourceType, resourceId); | |
20 | + } | |
21 | + | |
22 | + public static List<Watch> findBy(User user, ResourceType resourceType) { | |
23 | + return findBy(find, user, resourceType); | |
24 | + } | |
25 | +} |
--- app/models/enumeration/ResourceType.java
+++ app/models/enumeration/ResourceType.java
... | ... | @@ -27,7 +27,8 @@ |
27 | 27 |
FORK("fork"), |
28 | 28 |
CODE_COMMENT("code_comment"), |
29 | 29 |
PULL_REQUEST("pull_request"), |
30 |
- SIMPLE_COMMENT("simple_comment"); |
|
30 |
+ SIMPLE_COMMENT("simple_comment"), |
|
31 |
+ COMMIT("commit"); |
|
31 | 32 |
|
32 | 33 |
private String resource; |
33 | 34 |
|
--- app/models/resource/Resource.java
+++ app/models/resource/Resource.java
... | ... | @@ -1,10 +1,132 @@ |
1 | 1 |
package models.resource; |
2 | 2 |
|
3 |
-import models.Project; |
|
3 |
+import models.*; |
|
4 | 4 |
import models.enumeration.ResourceType; |
5 |
+import play.db.ebean.Model; |
|
6 |
+import play.libs.F; |
|
7 |
+import play.mvc.QueryStringBindable; |
|
8 |
+import playRepository.Commit; |
|
9 |
+import playRepository.RepositoryService; |
|
10 |
+ |
|
11 |
+import java.util.EnumSet; |
|
12 |
+import java.util.Map; |
|
5 | 13 |
|
6 | 14 |
public abstract class Resource { |
7 |
- abstract public Long getId(); |
|
15 |
+ public static boolean exists(ResourceType type, String id) { |
|
16 |
+ Model.Finder<Long, ? extends Model> finder = null; |
|
17 |
+ |
|
18 |
+ switch(type) { |
|
19 |
+ case ISSUE_POST: |
|
20 |
+ finder = Issue.finder; |
|
21 |
+ break; |
|
22 |
+ case ISSUE_ASSIGNEE: |
|
23 |
+ finder = Assignee.finder; |
|
24 |
+ break; |
|
25 |
+ case ISSUE_COMMENT: |
|
26 |
+ finder = IssueComment.find; |
|
27 |
+ break; |
|
28 |
+ case NONISSUE_COMMENT: |
|
29 |
+ finder = PostingComment.find; |
|
30 |
+ break; |
|
31 |
+ case LABEL: |
|
32 |
+ finder = Label.find; |
|
33 |
+ break; |
|
34 |
+ case BOARD_POST: |
|
35 |
+ finder = Posting.finder; |
|
36 |
+ break; |
|
37 |
+ case USER: |
|
38 |
+ finder = User.find; |
|
39 |
+ break; |
|
40 |
+ case PROJECT: |
|
41 |
+ finder = Project.find; |
|
42 |
+ break; |
|
43 |
+ case ATTACHMENT: |
|
44 |
+ finder = Attachment.find; |
|
45 |
+ break; |
|
46 |
+ case MILESTONE: |
|
47 |
+ finder = Milestone.find; |
|
48 |
+ break; |
|
49 |
+ case CODE_COMMENT: |
|
50 |
+ finder = CodeComment.find; |
|
51 |
+ break; |
|
52 |
+ case COMMIT: |
|
53 |
+ try { |
|
54 |
+ String[] pair = id.split(":"); |
|
55 |
+ Project project = Project.find.byId(Long.valueOf(pair[0])); |
|
56 |
+ if (RepositoryService.getRepository(project).getCommit(pair[1]) != null) { |
|
57 |
+ return true; |
|
58 |
+ } else { |
|
59 |
+ return false; |
|
60 |
+ } |
|
61 |
+ } catch (Exception e) { |
|
62 |
+ play.Logger.error("Failed to determine whether the commit exists", e); |
|
63 |
+ return false; |
|
64 |
+ } |
|
65 |
+ default: |
|
66 |
+ throw new IllegalArgumentException(getInvalidResourceTypeMessage(type)); |
|
67 |
+ } |
|
68 |
+ |
|
69 |
+ return finder.byId(Long.valueOf(id)) != null; |
|
70 |
+ } |
|
71 |
+ |
|
72 |
+ public static String getInvalidResourceTypeMessage(ResourceType resourceType) { |
|
73 |
+ if (EnumSet.allOf(ResourceType.class).contains(resourceType)) { |
|
74 |
+ return "Unsupported resource type " + resourceType; |
|
75 |
+ } else { |
|
76 |
+ return "Unknown resource type " + resourceType; |
|
77 |
+ } |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ public static Resource get(ResourceType resourceType, String resourceId) { |
|
81 |
+ Resource resource = null; |
|
82 |
+ |
|
83 |
+ Long longId = Long.valueOf(resourceId); |
|
84 |
+ |
|
85 |
+ switch(resourceType) { |
|
86 |
+ case ISSUE_POST: |
|
87 |
+ resource = Issue.finder.byId(longId).asResource(); |
|
88 |
+ break; |
|
89 |
+ case ISSUE_COMMENT: |
|
90 |
+ resource = IssueComment.find.byId(longId).asResource(); |
|
91 |
+ break; |
|
92 |
+ case NONISSUE_COMMENT: |
|
93 |
+ resource = PostingComment.find.byId(longId).asResource(); |
|
94 |
+ break; |
|
95 |
+ case LABEL: |
|
96 |
+ resource = Label.find.byId(longId).asResource(); |
|
97 |
+ break; |
|
98 |
+ case BOARD_POST: |
|
99 |
+ resource = Posting.finder.byId(longId).asResource(); |
|
100 |
+ break; |
|
101 |
+ case USER: |
|
102 |
+ resource = null; |
|
103 |
+ break; |
|
104 |
+ case PROJECT: |
|
105 |
+ resource = Project.find.byId(longId).asResource(); |
|
106 |
+ break; |
|
107 |
+ case ATTACHMENT: |
|
108 |
+ resource = Attachment.find.byId(longId).asResource(); |
|
109 |
+ break; |
|
110 |
+ case MILESTONE: |
|
111 |
+ resource = Milestone.find.byId(longId).asResource(); |
|
112 |
+ break; |
|
113 |
+ case CODE_COMMENT: |
|
114 |
+ resource = CodeComment.find.byId(longId).asResource(); |
|
115 |
+ break; |
|
116 |
+ case COMMIT: |
|
117 |
+ return Commit.getAsResource(resourceId); |
|
118 |
+ default: |
|
119 |
+ throw new IllegalArgumentException(getInvalidResourceTypeMessage(resourceType)); |
|
120 |
+ } |
|
121 |
+ |
|
122 |
+ return resource; |
|
123 |
+ } |
|
124 |
+ |
|
125 |
+ public ResourceParam asParameter() { |
|
126 |
+ return ResourceParam.get(this); |
|
127 |
+ } |
|
128 |
+ |
|
129 |
+ abstract public String getId(); |
|
8 | 130 |
abstract public Project getProject(); |
9 | 131 |
abstract public ResourceType getType(); |
10 | 132 |
public Resource getContainer() { return null; } |
+++ app/models/resource/ResourceParam.java
... | ... | @@ -0,0 +1,49 @@ |
1 | +package models.resource; | |
2 | + | |
3 | +import models.enumeration.ResourceType; | |
4 | +import play.libs.F; | |
5 | +import play.mvc.QueryStringBindable; | |
6 | + | |
7 | +import java.util.Map; | |
8 | + | |
9 | +/** | |
10 | +* Created with IntelliJ IDEA. | |
11 | +* User: nori | |
12 | +* Date: 13. 8. 13 | |
13 | +* Time: 오전 11:00 | |
14 | +* To change this template use File | Settings | File Templates. | |
15 | +*/ | |
16 | +public class ResourceParam implements QueryStringBindable<ResourceParam> { | |
17 | + | |
18 | + public Resource resource; | |
19 | + | |
20 | + public static ResourceParam get(Resource resource) { | |
21 | + ResourceParam resourceParam = new ResourceParam(); | |
22 | + resourceParam.resource = resource; | |
23 | + return resourceParam; | |
24 | + } | |
25 | + | |
26 | + @Override | |
27 | + public F.Option<ResourceParam> bind(String key, Map<String, String[]> data) { | |
28 | + String type = data.get(key + ".type")[0]; | |
29 | + String id = data.get(key + ".id")[0]; | |
30 | + Resource result = Resource.get(ResourceType.getValue(type), id); | |
31 | + if (result != null) { | |
32 | + return F.Some(ResourceParam.get(result)); | |
33 | + } else { | |
34 | + return new F.None<>(); | |
35 | + } | |
36 | + } | |
37 | + | |
38 | + @Override | |
39 | + public String unbind(String key) { | |
40 | + return String.format("%s.type=%s&%s.id=%s", | |
41 | + key, resource.getType().resource(), key, resource.getId()); | |
42 | + } | |
43 | + | |
44 | + @Override | |
45 | + public String javascriptUnbind() { | |
46 | + return "function(k,v) { return encodeURIComponent(k+'.type')+'='+v" + | |
47 | + ".resource.type+'&'+encodeURIComponent(k+'.id')+'='+v.resource.id; }"; | |
48 | + } | |
49 | +}(No newline at end of file) |
--- app/playRepository/Commit.java
+++ app/playRepository/Commit.java
... | ... | @@ -1,15 +1,12 @@ |
1 | 1 |
package playRepository; |
2 | 2 |
|
3 |
-import models.CodeComment; |
|
4 |
-import models.CommitExplicitWatching; |
|
5 |
-import models.Project; |
|
6 |
-import models.User; |
|
3 |
+import models.*; |
|
7 | 4 |
import models.enumeration.Operation; |
8 |
-import play.db.ebean.Model; |
|
5 |
+import models.enumeration.ResourceType; |
|
6 |
+import models.resource.Resource; |
|
9 | 7 |
import utils.AccessControl; |
8 |
+import utils.WatchService; |
|
10 | 9 |
|
11 |
-import javax.persistence.*; |
|
12 |
-import java.beans.Transient; |
|
13 | 10 |
import java.util.*; |
14 | 11 |
|
15 | 12 |
public abstract class Commit { |
... | ... | @@ -47,16 +44,12 @@ |
47 | 44 |
} |
48 | 45 |
} |
49 | 46 |
|
50 |
- // Add every user who watch the project to which this commit belongs |
|
51 |
- actualWatchers.addAll(project.watchers); |
|
47 |
+ // Add every user who watches the project to which this commit belongs |
|
48 |
+ actualWatchers.addAll(WatchService.findWatchers(project.asResource())); |
|
52 | 49 |
|
53 | 50 |
// For this commit, add every user who watch explicitly and remove who unwatch explicitly. |
54 |
- CommitExplicitWatching explicit = |
|
55 |
- CommitExplicitWatching.findByProjectAndCommitId(project, getId()); |
|
56 |
- if (explicit != null) { |
|
57 |
- actualWatchers.addAll(explicit.watchers); |
|
58 |
- actualWatchers.removeAll(explicit.unwatchers); |
|
59 |
- } |
|
51 |
+ actualWatchers.addAll(WatchService.findWatchers(asResource(project))); |
|
52 |
+ actualWatchers.removeAll(WatchService.findUnwatchers(asResource(project))); |
|
60 | 53 |
|
61 | 54 |
// Filter the watchers who has no permission to read this commit. |
62 | 55 |
Set<User> allowedWatchers = new HashSet<>(); |
... | ... | @@ -69,15 +62,48 @@ |
69 | 62 |
return allowedWatchers; |
70 | 63 |
} |
71 | 64 |
|
72 |
- public void watch(Project project, User user) { |
|
73 |
- CommitExplicitWatching explicit = CommitExplicitWatching.getOrCreate(project, getId()); |
|
74 |
- explicit.watchers.add(user); |
|
75 |
- explicit.update(); |
|
65 |
+ public static Project getProjectFromResourceId(String resourceId) { |
|
66 |
+ String[] pair = resourceId.split(":"); |
|
67 |
+ return Project.find.byId(Long.valueOf(pair[0])); |
|
76 | 68 |
} |
77 | 69 |
|
78 |
- public void unwatch(Project project, User user) { |
|
79 |
- CommitExplicitWatching explicit = CommitExplicitWatching.getOrCreate(project, getId()); |
|
80 |
- explicit.unwatchers.add(user); |
|
81 |
- explicit.update(); |
|
70 |
+ public static Resource getAsResource(final String resourceId) { |
|
71 |
+ return new Resource() { |
|
72 |
+ |
|
73 |
+ @Override |
|
74 |
+ public String getId() { |
|
75 |
+ return resourceId; |
|
76 |
+ } |
|
77 |
+ |
|
78 |
+ @Override |
|
79 |
+ public Project getProject() { |
|
80 |
+ return getProjectFromResourceId(resourceId); |
|
81 |
+ } |
|
82 |
+ |
|
83 |
+ @Override |
|
84 |
+ public ResourceType getType() { |
|
85 |
+ return ResourceType.COMMIT; |
|
86 |
+ } |
|
87 |
+ }; |
|
88 |
+ } |
|
89 |
+ |
|
90 |
+ public Resource asResource(final Project project) { |
|
91 |
+ return new Resource() { |
|
92 |
+ |
|
93 |
+ @Override |
|
94 |
+ public String getId() { |
|
95 |
+ return project.id + ":" + Commit.this.getId(); |
|
96 |
+ } |
|
97 |
+ |
|
98 |
+ @Override |
|
99 |
+ public Project getProject() { |
|
100 |
+ return project; |
|
101 |
+ } |
|
102 |
+ |
|
103 |
+ @Override |
|
104 |
+ public ResourceType getType() { |
|
105 |
+ return ResourceType.COMMIT; |
|
106 |
+ } |
|
107 |
+ }; |
|
82 | 108 |
} |
83 | 109 |
} |
--- app/playRepository/GitRepository.java
+++ app/playRepository/GitRepository.java
... | ... | @@ -323,7 +323,7 @@ |
323 | 323 |
LogCommand logCommand = git.log().add(untilCommitId); |
324 | 324 |
|
325 | 325 |
if (!basePath.isEmpty()) { |
326 |
- logCommand.addPath(basePath); |
|
326 |
+ logCommand.addPath(basePath); |
|
327 | 327 |
} |
328 | 328 |
|
329 | 329 |
Set<String> paths = new HashSet<>(); |
... | ... | @@ -551,7 +551,7 @@ |
551 | 551 |
public Resource asResource() { |
552 | 552 |
return new Resource() { |
553 | 553 |
@Override |
554 |
- public Long getId() { |
|
554 |
+ public String getId() { |
|
555 | 555 |
return null; |
556 | 556 |
} |
557 | 557 |
|
--- app/playRepository/SVNRepository.java
+++ app/playRepository/SVNRepository.java
... | ... | @@ -291,7 +291,7 @@ |
291 | 291 |
public Resource asResource() { |
292 | 292 |
return new Resource() { |
293 | 293 |
@Override |
294 |
- public Long getId() { |
|
294 |
+ public String getId() { |
|
295 | 295 |
return null; |
296 | 296 |
} |
297 | 297 |
|
--- app/utils/AccessControl.java
+++ app/utils/AccessControl.java
... | ... | @@ -92,7 +92,7 @@ |
92 | 92 |
|
93 | 93 |
if (operation == Operation.READ) { |
94 | 94 |
if (resource.getType() == ResourceType.PROJECT) { |
95 |
- Project project = Project.find.byId(resource.getId()); |
|
95 |
+ Project project = Project.find.byId(Long.valueOf(resource.getId())); |
|
96 | 96 |
return project != null && (project.isPublic || ProjectUser.isMember(user.id, project.id)); |
97 | 97 |
} |
98 | 98 |
|
... | ... | @@ -106,7 +106,7 @@ |
106 | 106 |
case USER_AVATAR: |
107 | 107 |
return user.id.equals(resource.getId()); |
108 | 108 |
case PROJECT: |
109 |
- return ProjectUser.isManager(user.id, resource.getId()); |
|
109 |
+ return ProjectUser.isManager(user.id, Long.valueOf(resource.getId())); |
|
110 | 110 |
default: |
111 | 111 |
// undefined |
112 | 112 |
return false; |
+++ app/utils/WatchService.java
... | ... | @@ -0,0 +1,126 @@ |
1 | +package utils; | |
2 | + | |
3 | +import com.avaje.ebean.annotation.Transactional; | |
4 | +import controllers.UserApp; | |
5 | +import models.Unwatch; | |
6 | +import models.User; | |
7 | +import models.Watch; | |
8 | +import models.enumeration.ResourceType; | |
9 | +import models.resource.Resource; | |
10 | + | |
11 | +import java.util.ArrayList; | |
12 | +import java.util.HashSet; | |
13 | +import java.util.List; | |
14 | +import java.util.Set; | |
15 | + | |
16 | +/** | |
17 | + * Created with IntelliJ IDEA. | |
18 | + * User: nori | |
19 | + * Date: 13. 8. 8 | |
20 | + * Time: 오후 1:25 | |
21 | + * To change this template use File | Settings | File Templates. | |
22 | + */ | |
23 | +public class WatchService { | |
24 | + public static void watch(Resource resource) { | |
25 | + watch(UserApp.currentUser(), resource); | |
26 | + } | |
27 | + | |
28 | + @Transactional | |
29 | + public static void watch(User user, Resource resource) { | |
30 | + watch(user, resource.getType(), resource.getId().toString()); | |
31 | + } | |
32 | + | |
33 | + public static void watch(User user, ResourceType resourceType, String resourceId) { | |
34 | + Watch watch = Watch.findBy(user, resourceType, resourceId); | |
35 | + if (watch == null) { | |
36 | + watch = new Watch(); | |
37 | + watch.user = user; | |
38 | + watch.resourceId = resourceId; | |
39 | + watch.resourceType = resourceType; | |
40 | + watch.save(); | |
41 | + } | |
42 | + | |
43 | + Unwatch unwatch = Unwatch.findBy(user, resourceType, resourceId); | |
44 | + if (unwatch != null) { | |
45 | + unwatch.delete(); | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + public static void unwatch(Resource resource) { | |
50 | + unwatch(UserApp.currentUser(), resource); | |
51 | + } | |
52 | + | |
53 | + public static void unwatch(User user, Resource resource) { | |
54 | + unwatch(user, resource.getType(), resource.getId().toString()); | |
55 | + } | |
56 | + | |
57 | + public static void unwatch(User user, ResourceType resourceType, String resourceId) { | |
58 | + Unwatch unwatch = Unwatch.findBy(user, resourceType, resourceId); | |
59 | + if (unwatch == null) { | |
60 | + unwatch = new Unwatch(); | |
61 | + unwatch.user = user; | |
62 | + unwatch.resourceId = resourceId; | |
63 | + unwatch.resourceType = resourceType; | |
64 | + unwatch.save(); | |
65 | + } | |
66 | + | |
67 | + Watch watch = Watch.findBy(user, resourceType, resourceId); | |
68 | + if (watch != null) { | |
69 | + watch.delete(); | |
70 | + } | |
71 | + } | |
72 | + | |
73 | + public static Set<User> findWatchers(Resource target) { | |
74 | + return findWatchers(target.getType(), target.getId().toString()); | |
75 | + } | |
76 | + | |
77 | + public static Set<User> findWatchers(ResourceType resourceType, String resourceId) { | |
78 | + HashSet<User> users = new HashSet<>(); | |
79 | + for (Watch watch: Watch.findBy(resourceType, resourceId)) { | |
80 | + users.add(watch.user); | |
81 | + } | |
82 | + return users; | |
83 | + } | |
84 | + | |
85 | + public static Set<User> findUnwatchers(Resource target) { | |
86 | + return findUnwatchers(target.getType(), target.getId().toString()); | |
87 | + } | |
88 | + | |
89 | + public static Set<User> findUnwatchers(ResourceType resourceType, String resourceId) { | |
90 | + HashSet<User> users = new HashSet<>(); | |
91 | + for (Unwatch unwatch: Unwatch.findBy(resourceType, resourceId)) { | |
92 | + users.add(unwatch.user); | |
93 | + } | |
94 | + return users; | |
95 | + } | |
96 | + | |
97 | + public static List<String> findWatchedResourceIds(User user, ResourceType resourceType) { | |
98 | + ArrayList<String> resourceIds = new ArrayList<>(); | |
99 | + for (Watch watch: Watch.findBy(user, resourceType)) { | |
100 | + resourceIds.add(watch.resourceId); | |
101 | + } | |
102 | + for (Unwatch unwatch: Unwatch.findBy(user, resourceType)) { | |
103 | + resourceIds.remove(unwatch.resourceId); | |
104 | + } | |
105 | + return resourceIds; | |
106 | + } | |
107 | + | |
108 | + public static boolean isWatching(User user, ResourceType resourceType, String resourceId) { | |
109 | + Watch watch = Watch.findBy(user, resourceType, resourceId); | |
110 | + Unwatch unwatch = Unwatch.findBy(user, resourceType, resourceId); | |
111 | + | |
112 | + if (watch != null && unwatch == null) { | |
113 | + return true; | |
114 | + } else { | |
115 | + return false; | |
116 | + } | |
117 | + } | |
118 | + | |
119 | + public static boolean isWatching(User user, Resource resource) { | |
120 | + return isWatching(user, resource.getType(), resource.getId().toString()); | |
121 | + } | |
122 | + | |
123 | + public static boolean isWatching(Resource resource) { | |
124 | + return isWatching(UserApp.currentUser(), resource.getType(), resource.getId().toString()); | |
125 | + } | |
126 | +} |
--- app/views/board/view.scala.html
+++ app/views/board/view.scala.html
... | ... | @@ -122,8 +122,8 @@ |
122 | 122 |
$(document).ready(function(){ |
123 | 123 |
$yobi.loadModule("board.View", { |
124 | 124 |
"sAction": "@routes.AttachmentApp.uploadFile", |
125 |
- "sWatchUrl" : "@routes.BoardApp.watch(project.owner, project.name, post.getNumber)", |
|
126 |
- "sUnwatchUrl" : "@routes.BoardApp.unwatch(project.owner, project.name, post.getNumber)" |
|
125 |
+ "sWatchUrl" : "@routes.WatchApp.watch(post.asResource.asParameter)", |
|
126 |
+ "sUnwatchUrl" : "@routes.WatchApp.unwatch(post.asResource.asParameter)" |
|
127 | 127 |
}); |
128 | 128 |
|
129 | 129 |
// yobi.ShortcutKey |
--- app/views/code/diff.scala.html
+++ app/views/code/diff.scala.html
... | ... | @@ -147,8 +147,8 @@ |
147 | 147 |
$yobi.loadModule("code.Diff", { |
148 | 148 |
"sAttachmentAction": "@routes.AttachmentApp.uploadFile", |
149 | 149 |
"bCommentable": bCommentable, |
150 |
- "sWatchUrl" : "@routes.CodeHistoryApp.watch(project.owner, project.name, commit.getId)", |
|
151 |
- "sUnwatchUrl" : "@routes.CodeHistoryApp.unwatch(project.owner, project.name, commit.getId)" |
|
150 |
+ "sWatchUrl" : "@routes.WatchApp.watch(commit.asResource(project).asParameter)", |
|
151 |
+ "sUnwatchUrl" : "@routes.WatchApp.unwatch(commit.asResource(project).asParameter)" |
|
152 | 152 |
}); |
153 | 153 |
|
154 | 154 |
yobi.Mention({ |
--- app/views/issue/view.scala.html
+++ app/views/issue/view.scala.html
... | ... | @@ -228,8 +228,8 @@ |
228 | 228 |
$yobi.loadModule("issue.View", { |
229 | 229 |
"sAction" : "@routes.AttachmentApp.uploadFile", |
230 | 230 |
"htOptLabel" : htOptLabel, |
231 |
- "sWatchUrl" : "@routes.IssueApp.watch(project.owner, project.name, issue.getNumber)", |
|
232 |
- "sUnwatchUrl" : "@routes.IssueApp.unwatch(project.owner, project.name, issue.getNumber)", |
|
231 |
+ "sWatchUrl" : "@routes.WatchApp.watch(issue.asResource.asParameter)", |
|
232 |
+ "sUnwatchUrl" : "@routes.WatchApp.unwatch(issue.asResource.asParameter)", |
|
233 | 233 |
"welMilestone" : $("#milestone"), |
234 | 234 |
"welAssignee" : $("#assignee"), |
235 | 235 |
"welIssueUpdateForm" : $("#issueUpdateForm"), |
+++ conf/evolutions/default/27.sql
... | ... | @@ -0,0 +1,55 @@ |
1 | +# --- !Ups | |
2 | + | |
3 | +create table watch ( | |
4 | + id bigint not null, | |
5 | + user_id bigint, | |
6 | + resource_type varchar(16), | |
7 | + resource_id varchar(255), | |
8 | + constraint ck_watch_resource_type check (resource_type in ('ISSUE_POST','ISSUE_ASSIGNEE','ISSUE_STATE','ISSUE_CATEGORY','ISSUE_MILESTONE','ISSUE_LABEL','BOARD_POST','BOARD_CATEGORY','BOARD_NOTICE','CODE','MILESTONE','WIKI_PAGE','PROJECT_SETTING','SITE_SETTING','USER','USER_AVATAR','PROJECT','ATTACHMENT','ISSUE_COMMENT','NONISSUE_COMMENT','LABEL','PROJECT_LABELS','FORK','CODE_COMMENT','PULL_REQUEST','SIMPLE_COMMENT', 'COMMIT')), | |
9 | + constraint pk_watch primary key (id)) | |
10 | +; | |
11 | + | |
12 | +create table unwatch ( | |
13 | + id bigint not null, | |
14 | + user_id bigint, | |
15 | + resource_type varchar(16), | |
16 | + resource_id varchar(255), | |
17 | + constraint ck_unwatch_resource_type check (resource_type in ('ISSUE_POST','ISSUE_ASSIGNEE','ISSUE_STATE','ISSUE_CATEGORY','ISSUE_MILESTONE','ISSUE_LABEL','BOARD_POST','BOARD_CATEGORY','BOARD_NOTICE','CODE','MILESTONE','WIKI_PAGE','PROJECT_SETTING','SITE_SETTING','USER','USER_AVATAR','PROJECT','ATTACHMENT','ISSUE_COMMENT','NONISSUE_COMMENT','LABEL','PROJECT_LABELS','FORK','CODE_COMMENT','PULL_REQUEST','SIMPLE_COMMENT', 'COMMIT')), | |
18 | + constraint pk_unwatch primary key (id)) | |
19 | +; | |
20 | + | |
21 | +create sequence watch_seq; | |
22 | + | |
23 | +create sequence unwatch_seq; | |
24 | + | |
25 | +alter table unwatch add constraint fk_unwatch_unwatcher_23 foreign key (user_id) references n4user (id) on delete restrict on update restrict; | |
26 | + | |
27 | +create index ix_unwatch_unwatcher_23 on unwatch (user_id); | |
28 | + | |
29 | +alter table watch add constraint fk_watch_watcher_24 foreign key (user_id) references n4user (id) on delete restrict on update restrict; | |
30 | + | |
31 | +create index ix_watch_watcher_24 on watch (user_id); | |
32 | + | |
33 | +drop table if exists user_watching_project; | |
34 | + | |
35 | +drop table if exists commit_explicit_watching; | |
36 | + | |
37 | +drop table if exists commit_explicit_watcher; | |
38 | + | |
39 | +drop table if exists commit_explicit_unwatcher; | |
40 | + | |
41 | +drop sequence if exists commit_explicit_watching_seq; | |
42 | + | |
43 | +ALTER TABLE attachment ALTER COLUMN container_id TYPE varchar(255); | |
44 | + | |
45 | +# --- !Downs | |
46 | + | |
47 | +drop table if exists unwatch; | |
48 | + | |
49 | +drop table if exists watch; | |
50 | + | |
51 | +drop sequence if exists unwatch_seq; | |
52 | + | |
53 | +drop sequence if exists watch_seq; | |
54 | + | |
55 | +ALTER TABLE attachment ALTER COLUMN container_id TYPE bigint; |
--- conf/routes
+++ conf/routes
... | ... | @@ -76,8 +76,6 @@ |
76 | 76 |
GET /:user/:project/post/:number/editform controllers.BoardApp.editPostForm(user, project, number:Long) |
77 | 77 |
POST /:user/:project/post/:number/edit controllers.BoardApp.editPost(user, project, number:Long) |
78 | 78 |
GET /:user/:project/post/:number/comment/:commentId/delete controllers.BoardApp.deleteComment(user, project, number:Long, commentId:Long) |
79 |
-POST /:user/:project/post/:number/watch controllers.BoardApp.watch(user, project, number:Long) |
|
80 |
-POST /:user/:project/post/:number/unwatch controllers.BoardApp.unwatch(user, project, number:Long) |
|
81 | 79 |
|
82 | 80 |
# Labels |
83 | 81 |
GET /labels controllers.LabelApp.labels(query: String ?= "", category: String ?= "", limit: Integer ?= null) |
... | ... | @@ -130,8 +128,6 @@ |
130 | 128 |
GET /:user/:project/issue/$number<[0-9]+>/delete controllers.IssueApp.deleteIssue(user, project, number:Long) |
131 | 129 |
POST /:user/:project/issue/$number<[0-9]+>/comments controllers.IssueApp.newComment(user, project, number:Long) |
132 | 130 |
GET /:user/:project/issue/$number<[0-9]+>/comment/:commentId/delete controllers.IssueApp.deleteComment(user, project, number:Long, commentId:Long) |
133 |
-POST /:user/:project/issue/$number<[0-9]+>/watch controllers.IssueApp.watch(user, project, number:Long) |
|
134 |
-POST /:user/:project/issue/$number<[0-9]+>/unwatch controllers.IssueApp.unwatch(user, project, number:Long) |
|
135 | 131 |
|
136 | 132 |
# Issue Labels |
137 | 133 |
GET /:user/:project/issue/labels controllers.IssueLabelApp.labels(user, project) |
... | ... | @@ -193,14 +189,15 @@ |
193 | 189 |
POST /:user/:project/commit/:commitId/comments controllers.CodeHistoryApp.newComment(user, project, commitId) |
194 | 190 |
GET /:user/:project/commit/:commitId/comments/:id/delete controllers.CodeHistoryApp.deleteComment(user, project, commitId, id: Long) |
195 | 191 |
|
196 |
-POST /:user/:project/commit/:id/watch controllers.CodeHistoryApp.watch(user, project, id) |
|
197 |
-POST /:user/:project/commit/:id/unwatch controllers.CodeHistoryApp.unwatch(user, project, id) |
|
198 |
- |
|
199 | 192 |
# Search |
200 | 193 |
GET /:user/:project/search controllers.SearchApp.contentsSearch(user, project, page: Int ?= 0) |
201 | 194 |
|
202 | 195 |
# Help |
203 | 196 |
GET /help controllers.HelpApp.help() |
197 |
+ |
|
198 |
+# Watch |
|
199 |
+POST /watch controllers.WatchApp.watch(resource: models.resource.ResourceParam) |
|
200 |
+POST /unwatch controllers.WatchApp.unwatch(resource: models.resource.ResourceParam) |
|
204 | 201 |
|
205 | 202 |
# Statistics |
206 | 203 |
GET /:user/:project/statistics controllers.StatisticsApp.statistics(user, project) |
... | ... | @@ -216,3 +213,4 @@ |
216 | 213 |
|
217 | 214 |
# remove trailing slash |
218 | 215 |
GET /*paths controllers.Application.removeTrailer(paths) |
216 |
+ |
--- test/controllers/IssueAppTest.java
+++ test/controllers/IssueAppTest.java
... | ... | @@ -1,6 +1,7 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 | 3 |
import models.*; |
4 |
+import models.resource.Resource; |
|
4 | 5 |
import org.junit.After; |
5 | 6 |
import org.junit.Before; |
6 | 7 |
import org.junit.BeforeClass; |
... | ... | @@ -312,9 +313,12 @@ |
312 | 313 |
|
313 | 314 |
@Test |
314 | 315 |
public void watch() { |
316 |
+ // Given |
|
317 |
+ Resource resource = issue.asResource(); |
|
318 |
+ |
|
315 | 319 |
// When |
316 | 320 |
Result result = callAction( |
317 |
- controllers.routes.ref.IssueApp.watch("yobi", "projectYobi", issue.getNumber()), |
|
321 |
+ controllers.routes.ref.WatchApp.watch(resource.asParameter()), |
|
318 | 322 |
fakeRequest() |
319 | 323 |
.withSession(UserApp.SESSION_USERID, nonmember.id.toString()) |
320 | 324 |
); |
... | ... | @@ -328,9 +332,12 @@ |
328 | 332 |
|
329 | 333 |
@Test |
330 | 334 |
public void unwatch() { |
335 |
+ // Given |
|
336 |
+ Resource resource = issue.asResource(); |
|
337 |
+ |
|
331 | 338 |
// When |
332 | 339 |
Result result = callAction( |
333 |
- controllers.routes.ref.IssueApp.unwatch("yobi", "projectYobi", issue.getNumber()), |
|
340 |
+ controllers.routes.ref.WatchApp.unwatch(resource.asParameter()), |
|
334 | 341 |
fakeRequest() |
335 | 342 |
.withSession(UserApp.SESSION_USERID, author.id.toString()) |
336 | 343 |
); |
--- test/controllers/WatchProjectAppTest.java
+++ test/controllers/WatchProjectAppTest.java
... | ... | @@ -133,12 +133,12 @@ |
133 | 133 |
private void assertProjectIsInUserWatchingProjects(String ownerName, |
134 | 134 |
String projectName, Long userId) { |
135 | 135 |
assertThat(Project.findByOwnerAndProjectName(ownerName, projectName)). |
136 |
- isIn(User.find.byId(userId).watchingProjects); |
|
136 |
+ isIn(User.find.byId(userId).getWatchingProjects()); |
|
137 | 137 |
} |
138 | 138 |
|
139 | 139 |
private void assertProjectIsNotInUserWatchingProjects(String ownerName, |
140 | 140 |
String projectName, Long userId) { |
141 | 141 |
assertThat(Project.findByOwnerAndProjectName(ownerName, projectName)). |
142 |
- isNotIn(User.find.byId(userId).watchingProjects); |
|
142 |
+ isNotIn(User.find.byId(userId).getWatchingProjects()); |
|
143 | 143 |
} |
144 |
-}(No newline at end of file) |
|
144 |
+} |
--- test/models/IssueTest.java
+++ test/models/IssueTest.java
... | ... | @@ -14,6 +14,7 @@ |
14 | 14 |
import com.avaje.ebean.Page; |
15 | 15 |
import play.Logger; |
16 | 16 |
import play.data.validation.Validation; |
17 |
+import utils.WatchService; |
|
17 | 18 |
|
18 | 19 |
public class IssueTest extends ModelTest<Issue> { |
19 | 20 |
private User admin; |
... | ... | @@ -85,13 +86,13 @@ |
85 | 86 |
|
86 | 87 |
@Test |
87 | 88 |
public void watchExplicitly() { |
88 |
- issue.watch(nonmember); |
|
89 |
+ WatchService.watch(nonmember, issue.asResource()); |
|
89 | 90 |
assertThat(issue.getWatchers().contains(nonmember)).isTrue(); |
90 | 91 |
} |
91 | 92 |
|
92 | 93 |
@Test |
93 | 94 |
public void unwatchExplicitly() { |
94 |
- issue.unwatch(author); |
|
95 |
+ WatchService.unwatch(author, issue.asResource()); |
|
95 | 96 |
assertThat(issue.getWatchers().contains(author)).isFalse(); |
96 | 97 |
} |
97 | 98 |
|
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?