[Notice] Announcing the End of Demo Server [Read me]

fixes a bug that users can agree to issues several times.
* Issue Users can agree to issues many times if the user clicks agree button very fast. Because there is no primary key on issue_voter table and logics checking voters duplicaiton. * Solution The primary key is added to issue_voter table. And to prevent vote duplication, protect codes are added. Altough issue_comment_voter table has a primary key, there are possibilities that primary key violation exception occur. So protect codes are added to issue_comment_voter table as issue_voter table. Private-issue: 2060
@6a6e6f74dad8e1c79c7f92d74d75f658e556ee4f
--- app/controllers/VoteApp.java
+++ app/controllers/VoteApp.java
... | ... | @@ -33,6 +33,7 @@ |
33 | 33 |
|
34 | 34 |
import java.util.ArrayList; |
35 | 35 |
import java.util.List; |
36 |
+import java.util.Set; |
|
36 | 37 |
|
37 | 38 |
/** |
38 | 39 |
* The Controller which plays a role in voting in the issue. |
... | ... | @@ -117,22 +118,17 @@ |
117 | 118 |
return redirect(RouteUtil.getUrl(issueComment)); |
118 | 119 |
} |
119 | 120 |
|
120 |
- public static List<User> getVotersForAvatar(List<User> voters, int size){ |
|
121 |
+ public static List<User> getVotersForAvatar(Set<User> voters, int size){ |
|
121 | 122 |
return getSubList(voters, 0, size); |
122 | 123 |
} |
123 | 124 |
|
124 |
- public static List<User> getVotersForName(List<User> voters, int fromIndex, int size){ |
|
125 |
+ public static List<User> getVotersForName(Set<User> voters, int fromIndex, int size){ |
|
125 | 126 |
return getSubList(voters, fromIndex, fromIndex + size); |
126 | 127 |
} |
127 | 128 |
|
128 |
- public static List<User> getVotersExceptCurrentUser(List<User> voters){ |
|
129 |
- List<User> result = new ArrayList<User>(voters); |
|
130 |
- |
|
131 |
- while(result.contains(UserApp.currentUser())){ |
|
132 |
- result.remove(UserApp.currentUser()); |
|
133 |
- } |
|
134 |
- |
|
135 |
- return result; |
|
129 |
+ public static Set<User> getVotersExceptCurrentUser(Set<User> voters){ |
|
130 |
+ voters.remove(UserApp.currentUser()); |
|
131 |
+ return voters; |
|
136 | 132 |
} |
137 | 133 |
|
138 | 134 |
/** |
... | ... | @@ -142,9 +138,9 @@ |
142 | 138 |
* @param toIndex |
143 | 139 |
* @return |
144 | 140 |
*/ |
145 |
- private static List<User> getSubList(List<User> voters, int fromIndex, int toIndex) { |
|
141 |
+ private static List<User> getSubList(Set<User> voters, int fromIndex, int toIndex) { |
|
146 | 142 |
try { |
147 |
- return voters.subList( |
|
143 |
+ return new ArrayList<>(voters).subList( |
|
148 | 144 |
Math.max(0, fromIndex), |
149 | 145 |
Math.min(voters.size(), toIndex) |
150 | 146 |
); |
--- app/models/Issue.java
+++ app/models/Issue.java
... | ... | @@ -95,7 +95,7 @@ |
95 | 95 |
joinColumns = @JoinColumn(name = "issue_id"), |
96 | 96 |
inverseJoinColumns = @JoinColumn(name = "user_id") |
97 | 97 |
) |
98 |
- public List<User> voters = new ArrayList<>(); |
|
98 |
+ public Set<User> voters = new HashSet<>(); |
|
99 | 99 |
|
100 | 100 |
@Transient |
101 | 101 |
@Formula(select = "case when due_date is null then cast('0001-01-01 00:00:00' as timestamp) else due_date end") |
... | ... | @@ -470,8 +470,9 @@ |
470 | 470 |
* @param user |
471 | 471 |
*/ |
472 | 472 |
public void addVoter(User user) { |
473 |
- this.voters.add(user); |
|
474 |
- this.update(); |
|
473 |
+ if (voters.add(user)) { |
|
474 |
+ update(); |
|
475 |
+ } |
|
475 | 476 |
} |
476 | 477 |
|
477 | 478 |
/** |
... | ... | @@ -480,8 +481,9 @@ |
480 | 481 |
* @param user |
481 | 482 |
*/ |
482 | 483 |
public void removeVoter(User user) { |
483 |
- this.voters.remove(user); |
|
484 |
- this.update(); |
|
484 |
+ if (voters.remove(user)) { |
|
485 |
+ update(); |
|
486 |
+ } |
|
485 | 487 |
} |
486 | 488 |
|
487 | 489 |
/** |
--- app/models/IssueComment.java
+++ app/models/IssueComment.java
... | ... | @@ -24,7 +24,8 @@ |
24 | 24 |
import models.resource.Resource; |
25 | 25 |
|
26 | 26 |
import javax.persistence.*; |
27 |
-import java.util.List; |
|
27 |
+import java.util.HashSet; |
|
28 |
+import java.util.Set; |
|
28 | 29 |
|
29 | 30 |
@Entity |
30 | 31 |
public class IssueComment extends Comment { |
... | ... | @@ -40,7 +41,7 @@ |
40 | 41 |
joinColumns = @JoinColumn(name = "issue_comment_id"), |
41 | 42 |
inverseJoinColumns = @JoinColumn(name = "user_id") |
42 | 43 |
) |
43 |
- public List<User> voters; |
|
44 |
+ public Set<User> voters = new HashSet<>(); |
|
44 | 45 |
|
45 | 46 |
public IssueComment(Issue issue, User author, String contents) { |
46 | 47 |
super(author, contents); |
... | ... | @@ -88,16 +89,14 @@ |
88 | 89 |
} |
89 | 90 |
|
90 | 91 |
public void addVoter(User user) { |
91 |
- if (!this.voters.contains(user)) { |
|
92 |
- this.voters.add(user); |
|
93 |
- this.update(); |
|
92 |
+ if (voters.add(user)) { |
|
93 |
+ update(); |
|
94 | 94 |
} |
95 | 95 |
} |
96 | 96 |
|
97 | 97 |
public void removeVoter(User user) { |
98 |
- if (this.voters.contains(user)) { |
|
99 |
- this.voters.remove(user); |
|
100 |
- this.update(); |
|
98 |
+ if (voters.remove(user)) { |
|
99 |
+ update(); |
|
101 | 100 |
} |
102 | 101 |
} |
103 | 102 |
} |
+++ conf/evolutions/default/97.sql
... | ... | @@ -0,0 +1,18 @@ |
1 | +# --- !Ups | |
2 | + | |
3 | +create table issue_voter_temp ( | |
4 | + issue_id bigint not null, | |
5 | + user_id bigint not null | |
6 | +); | |
7 | + | |
8 | +insert into issue_voter_temp select * from issue_voter group by issue_id, user_id; | |
9 | +drop table issue_voter; | |
10 | +alter table issue_voter_temp rename to issue_voter; | |
11 | + | |
12 | +alter table issue_voter add constraint pk_issue_voter primary key (issue_id, user_id); | |
13 | +alter table issue_voter add constraint fk_issue_voter_issue_1 foreign key (issue_id) references issue (id) on delete restrict on update restrict; | |
14 | +alter table issue_voter add constraint fk_issue_voter_n4user_2 foreign key (user_id) references n4user (id) on delete restrict on update restrict; | |
15 | + | |
16 | +# --- !Downs | |
17 | + | |
18 | +alter table issue_voter drop constraint if exists pk_issue_voter; |
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?