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

Merge pull request #172 from whiteship/yobi refs/heads/pullrequest-tab
@2d9caf40f1e535a09fb38a98d12ba25e3ea9c550
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
... | ... | @@ -3183,16 +3183,16 @@ |
3183 | 3183 |
margin-bottom: 3px; |
3184 | 3184 |
} |
3185 | 3185 |
|
3186 |
- > div { |
|
3187 |
- display: table-cell; |
|
3188 |
- vertical-align: middle; |
|
3189 |
- } |
|
3190 |
- .num { |
|
3186 |
+ .board-id { |
|
3191 | 3187 |
width: 35px; |
3192 | 3188 |
color: #B2B2B2; |
3193 | 3189 |
vertical-align: middle; |
3194 | 3190 |
font-size: 12px; |
3191 |
+ float:left; |
|
3192 |
+ line-height: 20px; |
|
3193 |
+ padding: 10px 0; |
|
3195 | 3194 |
} |
3195 |
+ |
|
3196 | 3196 |
.attach-wrap { |
3197 | 3197 |
width: 35px; |
3198 | 3198 |
text-align: center; |
... | ... | @@ -3200,28 +3200,45 @@ |
3200 | 3200 |
margin-top: 5px; |
3201 | 3201 |
} |
3202 | 3202 |
} |
3203 |
+ |
|
3204 |
+ .author-avatar-space{ |
|
3205 |
+ width:38px; |
|
3206 |
+ height:38px; |
|
3207 |
+ float:left; |
|
3208 |
+ padding-right: 10px; |
|
3209 |
+ |
|
3210 |
+ .img-rounded { |
|
3211 |
+ .inline-block; |
|
3212 |
+ vertical-align:top; |
|
3213 |
+ width:100%; |
|
3214 |
+ height:100%; |
|
3215 |
+ } |
|
3216 |
+ } |
|
3217 |
+ |
|
3203 | 3218 |
.contents { |
3204 |
- width: 80%;/*720px;*/ |
|
3205 |
- padding-right: 20px; |
|
3219 |
+ margin-left: 100px; |
|
3206 | 3220 |
|
3207 | 3221 |
label { |
3208 | 3222 |
display:block; |
3209 | 3223 |
margin:0;padding:0; |
3210 | 3224 |
} |
3225 |
+ |
|
3211 | 3226 |
.title { |
3212 | 3227 |
margin-bottom: 5px; |
3213 | 3228 |
font-weight: bold; |
3214 | 3229 |
font-size: 15px; |
3230 |
+ |
|
3215 | 3231 |
.label-notice { |
3216 | 3232 |
background:@secondary; |
3217 | 3233 |
} |
3234 |
+ |
|
3218 | 3235 |
a { |
3219 |
- overflow:hidden; |
|
3220 |
- text-overflow:clip; /*ellipsis;*/ |
|
3221 |
- -webkit-line-clamp:4; |
|
3222 |
- -webkit-box-orient:vertical; |
|
3236 |
+ text-overflow: ellipsis; |
|
3237 |
+ white-space: nowrap; |
|
3238 |
+ overflow: hidden; |
|
3223 | 3239 |
} |
3224 | 3240 |
} |
3241 |
+ |
|
3225 | 3242 |
.infos { |
3226 | 3243 |
line-height: 14px; |
3227 | 3244 |
font-size: 11px; |
... | ... | @@ -3238,54 +3255,6 @@ |
3238 | 3255 |
.num { color: @secondary; font-weight:bold; } |
3239 | 3256 |
.icon { margin-right: 3px; color : #51aacc; } |
3240 | 3257 |
} |
3241 |
- } |
|
3242 |
- } |
|
3243 |
- .author-avatar-space{ |
|
3244 |
- width:32px; |
|
3245 |
- padding-right: 10px; |
|
3246 |
- .img-rounded { |
|
3247 |
- .inline-block; |
|
3248 |
- width:40px; height:40px; |
|
3249 |
- } |
|
3250 |
- } |
|
3251 |
- .right-panel { |
|
3252 |
- width: 160px; |
|
3253 |
- padding-right: 10px; |
|
3254 |
- .state { |
|
3255 |
- float:right; |
|
3256 |
- margin-top:7px; |
|
3257 |
- margin-right:13px; |
|
3258 |
- font-weight:bold; |
|
3259 |
- font-size:11px; |
|
3260 |
- color:#bbb; width:38px; |
|
3261 |
- &.open { |
|
3262 |
- color:@blue; |
|
3263 |
- } |
|
3264 |
- } |
|
3265 |
- .avatar-wrap { |
|
3266 |
- float: right; |
|
3267 |
- } |
|
3268 |
- .empty-avatar-space{ |
|
3269 |
- width:32px; |
|
3270 |
- display:inline-block; |
|
3271 |
- float:right |
|
3272 |
- } |
|
3273 |
- .comment-wrap { |
|
3274 |
- float: right; |
|
3275 |
- margin-top: 7px; |
|
3276 |
- margin-right:15px; |
|
3277 |
- |
|
3278 |
- .ico { |
|
3279 |
- vertical-align: bottom; |
|
3280 |
- margin-right: 5px; |
|
3281 |
- } |
|
3282 |
- .num { |
|
3283 |
- color: #4489A4; |
|
3284 |
- } |
|
3285 |
- } |
|
3286 |
- .img-rounded { |
|
3287 |
- .inline-block; |
|
3288 |
- width:32px; height:32px; |
|
3289 | 3258 |
} |
3290 | 3259 |
} |
3291 | 3260 |
} |
... | ... | @@ -4608,8 +4577,12 @@ |
4608 | 4577 |
width: 40px; |
4609 | 4578 |
} |
4610 | 4579 |
.filename { float:left; line-height:30px; } |
4580 |
+ |
|
4581 |
+ .hide { |
|
4582 |
+ display:none; |
|
4583 |
+ } |
|
4611 | 4584 |
} |
4612 | 4585 |
|
4613 | 4586 |
div.diff-body[data-outdated="true"] tr:hover .icon-comment { |
4614 | 4587 |
visibility: hidden; |
4615 |
-} |
|
4588 |
+}(No newline at end of file) |
--- app/controllers/CodeHistoryApp.java
+++ app/controllers/CodeHistoryApp.java
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 |
import models.enumeration.Operation; |
13 | 13 |
|
14 | 14 |
import models.enumeration.ResourceType; |
15 |
+import org.apache.commons.lang.StringUtils; |
|
15 | 16 |
import org.eclipse.jgit.api.errors.GitAPIException; |
16 | 17 |
import org.eclipse.jgit.api.errors.NoHeadException; |
17 | 18 |
import org.tmatesoft.svn.core.SVNException; |
... | ... | @@ -154,7 +155,10 @@ |
154 | 155 |
Commit commit = repository.getCommit(commitId); |
155 | 156 |
Commit parentCommit = repository.getParentCommitOf(commitId); |
156 | 157 |
List<CommitComment> comments = CommitComment.find.where().eq("commitId", |
157 |
- commitId).eq("project.id", project.id).findList(); |
|
158 |
+ commitId).eq("project.id", project.id).order("createdDate").findList(); |
|
159 |
+ |
|
160 |
+ String selectedBranch = StringUtils.defaultIfBlank(request().getQueryString("branch"), "HEAD"); |
|
161 |
+ String path = StringUtils.defaultIfBlank(request().getQueryString("path"), ""); |
|
158 | 162 |
|
159 | 163 |
if(project.vcs.equals(RepositoryService.VCS_SUBVERSION)) { |
160 | 164 |
String patch = repository.getPatch(commitId); |
... | ... | @@ -163,9 +167,7 @@ |
163 | 167 |
return notFound(ErrorViews.NotFound.render("error.notfound", project)); |
164 | 168 |
} |
165 | 169 |
|
166 |
- String selectedBranch = request().getQueryString("branch"); |
|
167 |
- |
|
168 |
- return ok(svnDiff.render(project, commit, parentCommit, patch, comments, selectedBranch)); |
|
170 |
+ return ok(svnDiff.render(project, commit, parentCommit, patch, comments, selectedBranch, path)); |
|
169 | 171 |
} else { |
170 | 172 |
List<FileDiff> fileDiffs = repository.getDiff(commitId); |
171 | 173 |
|
... | ... | @@ -173,9 +175,7 @@ |
173 | 175 |
return notFound(ErrorViews.NotFound.render("error.notfound", project)); |
174 | 176 |
} |
175 | 177 |
|
176 |
- String selectedBranch = request().getQueryString("branch"); |
|
177 |
- |
|
178 |
- return ok(diff.render(project, commit, parentCommit, comments, selectedBranch, fileDiffs)); |
|
178 |
+ return ok(diff.render(project, commit, parentCommit, comments, selectedBranch, fileDiffs, path)); |
|
179 | 179 |
} |
180 | 180 |
} |
181 | 181 |
|
--- app/controllers/PullRequestApp.java
+++ app/controllers/PullRequestApp.java
... | ... | @@ -534,13 +534,13 @@ |
534 | 534 |
|
535 | 535 |
Call call = routes.PullRequestApp.pullRequest(userName, projectName, pullRequestNumber); |
536 | 536 |
|
537 |
- addNotification(pullRequest, call); |
|
537 |
+ addNotification(pullRequest, call, State.OPEN, State.CLOSED); |
|
538 | 538 |
|
539 | 539 |
return redirect(call); |
540 | 540 |
} |
541 | 541 |
|
542 |
- private static void addNotification(PullRequest pullRequest, Call call) { |
|
543 |
- NotificationEvent notiEvent = NotificationEvent.addPullRequestUpdate(call, request(), pullRequest, State.OPEN, State.CLOSED); |
|
542 |
+ private static void addNotification(PullRequest pullRequest, Call call, State from, State to) { |
|
543 |
+ NotificationEvent notiEvent = NotificationEvent.addPullRequestUpdate(call, request(), pullRequest, from, to); |
|
544 | 544 |
PullRequestEvent.addEvent(notiEvent, pullRequest); |
545 | 545 |
} |
546 | 546 |
|
... | ... | @@ -567,7 +567,7 @@ |
567 | 567 |
|
568 | 568 |
Call call = routes.PullRequestApp.pullRequest(userName, projectName, pullRequestNumber); |
569 | 569 |
|
570 |
- addNotification(pullRequest, call); |
|
570 |
+ addNotification(pullRequest, call, State.OPEN, State.REJECTED); |
|
571 | 571 |
|
572 | 572 |
return redirect(call); |
573 | 573 |
} |
... | ... | @@ -595,7 +595,7 @@ |
595 | 595 |
|
596 | 596 |
Call call = routes.PullRequestApp.pullRequest(userName, projectName, pullRequestNumber); |
597 | 597 |
|
598 |
- addNotification(pullRequest, call); |
|
598 |
+ addNotification(pullRequest, call, State.REJECTED, State.OPEN); |
|
599 | 599 |
|
600 | 600 |
return redirect(call); |
601 | 601 |
} |
... | ... | @@ -775,7 +775,7 @@ |
775 | 775 |
} |
776 | 776 |
|
777 | 777 |
List<CommitComment> comments = CommitComment.find.where().eq("commitId", |
778 |
- commitId).eq("project.id", project.id).findList(); |
|
778 |
+ commitId).eq("project.id", project.id).order("createdDate").findList(); |
|
779 | 779 |
|
780 | 780 |
return ok(diff.render(pullRequest, commit, parentCommit, fileDiffs, comments)); |
781 | 781 |
} |
--- app/models/Attachment.java
+++ app/models/Attachment.java
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 |
|
13 | 13 |
import javax.persistence.*; |
14 | 14 |
|
15 |
+import models.resource.GlobalResource; |
|
15 | 16 |
import models.resource.Resource; |
16 | 17 |
import models.resource.ResourceConvertible; |
17 | 18 |
|
... | ... | @@ -143,10 +144,10 @@ |
143 | 144 |
* @return |
144 | 145 |
*/ |
145 | 146 |
public void moveTo(Resource to) { |
146 |
- if(to.getProject() != null) { |
|
147 |
- projectId = to.getProject().id; |
|
148 |
- } else { |
|
147 |
+ if (to instanceof GlobalResource) { |
|
149 | 148 |
projectId = null; |
149 |
+ } else { |
|
150 |
+ projectId = to.getProject().id; |
|
150 | 151 |
} |
151 | 152 |
containerType = to.getType(); |
152 | 153 |
containerId = to.getId(); |
... | ... | @@ -223,9 +224,9 @@ |
223 | 224 |
public boolean store(File file, String name, Resource container) throws IOException, NoSuchAlgorithmException { |
224 | 225 |
// Store the file as its SHA1 hash in filesystem, and record its |
225 | 226 |
// metadata - projectId, containerType, containerId, size and hash - in Database. |
226 |
- |
|
227 |
- Project project = container.getProject(); |
|
228 |
- this.projectId = project == null ? 0L : project.id; |
|
227 |
+ if (!(container instanceof GlobalResource)) { |
|
228 |
+ this.projectId = container.getProject().id; |
|
229 |
+ } |
|
229 | 230 |
this.containerType = container.getType(); |
230 | 231 |
this.containerId = container.getId(); |
231 | 232 |
|
... | ... | @@ -325,50 +326,70 @@ |
325 | 326 |
*/ |
326 | 327 |
@Override |
327 | 328 |
public Resource asResource() { |
328 |
- return new Resource() { |
|
329 |
- @Override |
|
330 |
- public String getId() { |
|
331 |
- return id.toString(); |
|
332 |
- } |
|
333 |
- |
|
334 |
- @Override |
|
335 |
- public Project getProject() { |
|
336 |
- if (projectId != null) { |
|
337 |
- return Project.find.byId(projectId); |
|
338 |
- } else { |
|
339 |
- return null; |
|
329 |
+ if (projectId == null) { |
|
330 |
+ return new GlobalResource() { |
|
331 |
+ @Override |
|
332 |
+ public String getId() { |
|
333 |
+ return id.toString(); |
|
340 | 334 |
} |
341 |
- } |
|
342 | 335 |
|
343 |
- @Override |
|
344 |
- public ResourceType getType() { |
|
345 |
- return ResourceType.ATTACHMENT; |
|
346 |
- } |
|
336 |
+ @Override |
|
337 |
+ public ResourceType getType() { |
|
338 |
+ return ResourceType.ATTACHMENT; |
|
339 |
+ } |
|
347 | 340 |
|
348 |
- @Override |
|
349 |
- public Resource getContainer() { |
|
350 |
- return new Resource() { |
|
351 |
- |
|
352 |
- @Override |
|
353 |
- public String getId() { |
|
354 |
- return containerId; |
|
355 |
- } |
|
356 |
- |
|
357 |
- @Override |
|
358 |
- public Project getProject() { |
|
359 |
- if (projectId != null) { |
|
360 |
- return Project.find.byId(projectId); |
|
361 |
- } else { |
|
362 |
- return null; |
|
341 |
+ @Override |
|
342 |
+ public Resource getContainer() { |
|
343 |
+ return new GlobalResource() { |
|
344 |
+ @Override |
|
345 |
+ public String getId() { |
|
346 |
+ return containerId; |
|
363 | 347 |
} |
364 |
- } |
|
365 | 348 |
|
366 |
- @Override |
|
367 |
- public ResourceType getType() { |
|
368 |
- return containerType; |
|
369 |
- } |
|
370 |
- }; |
|
371 |
- } |
|
372 |
- }; |
|
349 |
+ @Override |
|
350 |
+ public ResourceType getType() { |
|
351 |
+ return containerType; |
|
352 |
+ } |
|
353 |
+ }; |
|
354 |
+ } |
|
355 |
+ }; |
|
356 |
+ } else { |
|
357 |
+ return new Resource() { |
|
358 |
+ @Override |
|
359 |
+ public String getId() { |
|
360 |
+ return id.toString(); |
|
361 |
+ } |
|
362 |
+ |
|
363 |
+ @Override |
|
364 |
+ public Project getProject() { |
|
365 |
+ return Project.find.byId(projectId); |
|
366 |
+ } |
|
367 |
+ |
|
368 |
+ @Override |
|
369 |
+ public ResourceType getType() { |
|
370 |
+ return ResourceType.ATTACHMENT; |
|
371 |
+ } |
|
372 |
+ |
|
373 |
+ @Override |
|
374 |
+ public Resource getContainer() { |
|
375 |
+ return new Resource() { |
|
376 |
+ @Override |
|
377 |
+ public String getId() { |
|
378 |
+ return containerId; |
|
379 |
+ } |
|
380 |
+ |
|
381 |
+ @Override |
|
382 |
+ public Project getProject() { |
|
383 |
+ return Project.find.byId(projectId); |
|
384 |
+ } |
|
385 |
+ |
|
386 |
+ @Override |
|
387 |
+ public ResourceType getType() { |
|
388 |
+ return containerType; |
|
389 |
+ } |
|
390 |
+ }; |
|
391 |
+ } |
|
392 |
+ }; |
|
393 |
+ } |
|
373 | 394 |
} |
374 | 395 |
} |
--- app/models/Label.java
+++ app/models/Label.java
... | ... | @@ -1,6 +1,7 @@ |
1 | 1 |
package models; |
2 | 2 |
|
3 | 3 |
import models.enumeration.ResourceType; |
4 |
+import models.resource.GlobalResource; |
|
4 | 5 |
import models.resource.Resource; |
5 | 6 |
import models.resource.ResourceConvertible; |
6 | 7 |
import play.data.validation.Constraints.Required; |
... | ... | @@ -98,15 +99,10 @@ |
98 | 99 |
*/ |
99 | 100 |
@Override |
100 | 101 |
public Resource asResource() { |
101 |
- return new Resource() { |
|
102 |
+ return new GlobalResource() { |
|
102 | 103 |
@Override |
103 | 104 |
public String getId() { |
104 | 105 |
return id.toString(); |
105 |
- } |
|
106 |
- |
|
107 |
- @Override |
|
108 |
- public Project getProject() { |
|
109 |
- return null; |
|
110 | 106 |
} |
111 | 107 |
|
112 | 108 |
@Override |
--- app/models/NotificationEvent.java
+++ app/models/NotificationEvent.java
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 |
import models.enumeration.RequestState; |
5 | 5 |
import models.enumeration.ResourceType; |
6 | 6 |
import models.enumeration.State; |
7 |
+import models.resource.GlobalResource; |
|
7 | 8 |
import models.resource.Resource; |
8 | 9 |
import org.apache.commons.lang3.StringUtils; |
9 | 10 |
import org.joda.time.DateTime; |
... | ... | @@ -186,7 +187,11 @@ |
186 | 187 |
default: |
187 | 188 |
Resource resource = getResource(); |
188 | 189 |
if (resource != null) { |
189 |
- return resource.getProject(); |
|
190 |
+ if (resource instanceof GlobalResource) { |
|
191 |
+ return null; |
|
192 |
+ } else { |
|
193 |
+ return resource.getProject(); |
|
194 |
+ } |
|
190 | 195 |
} else { |
191 | 196 |
return null; |
192 | 197 |
} |
--- app/models/NullUser.java
+++ app/models/NullUser.java
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 |
|
3 | 3 |
import controllers.UserApp; |
4 | 4 |
import models.enumeration.ResourceType; |
5 |
+import models.resource.GlobalResource; |
|
5 | 6 |
import models.resource.Resource; |
6 | 7 |
import play.i18n.Messages; |
7 | 8 |
|
... | ... | @@ -31,15 +32,10 @@ |
31 | 32 |
|
32 | 33 |
@Override |
33 | 34 |
public Resource asResource() { |
34 |
- return new Resource() { |
|
35 |
+ return new GlobalResource() { |
|
35 | 36 |
@Override |
36 | 37 |
public String getId() { |
37 | 38 |
return id.toString(); |
38 |
- } |
|
39 |
- |
|
40 |
- @Override |
|
41 |
- public Project getProject() { |
|
42 |
- return null; |
|
43 | 39 |
} |
44 | 40 |
|
45 | 41 |
@Override |
--- app/models/Project.java
+++ app/models/Project.java
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 |
import models.enumeration.RequestState; |
10 | 10 |
import models.enumeration.ResourceType; |
11 | 11 |
import models.enumeration.RoleType; |
12 |
+import models.resource.GlobalResource; |
|
12 | 13 |
import models.resource.Resource; |
13 | 14 |
|
14 | 15 |
import org.apache.commons.lang3.StringUtils; |
... | ... | @@ -485,16 +486,11 @@ |
485 | 486 |
*/ |
486 | 487 |
@Override |
487 | 488 |
public Resource asResource() { |
488 |
- return new Resource() { |
|
489 |
+ return new GlobalResource() { |
|
489 | 490 |
|
490 | 491 |
@Override |
491 | 492 |
public String getId() { |
492 | 493 |
return id.toString(); |
493 |
- } |
|
494 |
- |
|
495 |
- @Override |
|
496 |
- public Project getProject() { |
|
497 |
- return null; |
|
498 | 494 |
} |
499 | 495 |
|
500 | 496 |
@Override |
... | ... | @@ -753,6 +749,14 @@ |
753 | 749 |
label.delete(); |
754 | 750 |
} |
755 | 751 |
|
752 |
+ for(Issue issue : issues) { |
|
753 |
+ issue.delete(); |
|
754 |
+ } |
|
755 |
+ |
|
756 |
+ for(Posting posting : posts) { |
|
757 |
+ posting.delete(); |
|
758 |
+ } |
|
759 |
+ |
|
756 | 760 |
super.delete(); |
757 | 761 |
} |
758 | 762 |
|
--- app/models/PullRequestComment.java
+++ app/models/PullRequestComment.java
... | ... | @@ -79,7 +79,7 @@ |
79 | 79 |
|
80 | 80 |
@Override |
81 | 81 |
public Project getProject() { |
82 |
- return null; |
|
82 |
+ return pullRequest.asResource().getProject(); |
|
83 | 83 |
} |
84 | 84 |
|
85 | 85 |
@Override |
--- app/models/User.java
+++ app/models/User.java
... | ... | @@ -7,6 +7,7 @@ |
7 | 7 |
|
8 | 8 |
import controllers.UserApp; |
9 | 9 |
import models.enumeration.*; |
10 |
+import models.resource.GlobalResource; |
|
10 | 11 |
import models.resource.Resource; |
11 | 12 |
import models.resource.ResourceConvertible; |
12 | 13 |
import models.support.FinderTemplate; |
... | ... | @@ -319,15 +320,10 @@ |
319 | 320 |
*/ |
320 | 321 |
@Override |
321 | 322 |
public Resource asResource() { |
322 |
- return new Resource() { |
|
323 |
+ return new GlobalResource() { |
|
323 | 324 |
@Override |
324 | 325 |
public String getId() { |
325 | 326 |
return id.toString(); |
326 |
- } |
|
327 |
- |
|
328 |
- @Override |
|
329 |
- public Project getProject() { |
|
330 |
- return null; |
|
331 | 327 |
} |
332 | 328 |
|
333 | 329 |
@Override |
... | ... | @@ -338,15 +334,10 @@ |
338 | 334 |
} |
339 | 335 |
|
340 | 336 |
public Resource avatarAsResource() { |
341 |
- return new Resource() { |
|
337 |
+ return new GlobalResource() { |
|
342 | 338 |
@Override |
343 | 339 |
public String getId() { |
344 | 340 |
return id.toString(); |
345 |
- } |
|
346 |
- |
|
347 |
- @Override |
|
348 |
- public Project getProject() { |
|
349 |
- return null; |
|
350 | 341 |
} |
351 | 342 |
|
352 | 343 |
@Override |
+++ app/models/resource/GlobalResource.java
... | ... | @@ -0,0 +1,12 @@ |
1 | +package models.resource; | |
2 | + | |
3 | +import models.Project; | |
4 | +import models.enumeration.ResourceType; | |
5 | +import models.resource.Resource; | |
6 | + | |
7 | +abstract public class GlobalResource extends Resource { | |
8 | + @Override | |
9 | + public Project getProject() { | |
10 | + throw new UnsupportedOperationException(); | |
11 | + } | |
12 | +} |
--- app/playRepository/GitRepository.java
+++ app/playRepository/GitRepository.java
... | ... | @@ -483,9 +483,13 @@ |
483 | 483 |
|
484 | 484 |
/** |
485 | 485 |
* Git 저장소 디렉토리를 삭제한다. |
486 |
+ * 변경전 {@code repository.close()}를 통해 open된 repository의 리소스를 반환하고 |
|
487 |
+ * repository 내부에서 사용하는 {@code Cache}를 초기화하여 packFile의 참조를 제거한다. |
|
486 | 488 |
*/ |
487 | 489 |
@Override |
488 | 490 |
public void delete() { |
491 |
+ repository.close(); |
|
492 |
+ WindowCache.reconfigure(new WindowCacheConfig()); |
|
489 | 493 |
FileUtil.rm_rf(repository.getDirectory()); |
490 | 494 |
} |
491 | 495 |
|
--- app/utils/AccessControl.java
+++ app/utils/AccessControl.java
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 |
import models.enumeration.Operation; |
5 | 5 |
import models.enumeration.ResourceType; |
6 | 6 |
|
7 |
+import models.resource.GlobalResource; |
|
7 | 8 |
import models.resource.Resource; |
8 | 9 |
|
9 | 10 |
public class AccessControl { |
... | ... | @@ -84,7 +85,8 @@ |
84 | 85 |
* @param operation |
85 | 86 |
* @return |
86 | 87 |
*/ |
87 |
- private static boolean isGlobalResourceAllowed(User user, Resource resource, Operation operation) { |
|
88 |
+ private static boolean isGlobalResourceAllowed(User user, GlobalResource resource, |
|
89 |
+ Operation operation) { |
|
88 | 90 |
// Temporary attachments are allowed only for the user who uploads them. |
89 | 91 |
if (resource.getType() == ResourceType.ATTACHMENT |
90 | 92 |
&& resource.getContainer().getType() == ResourceType.USER) { |
... | ... | @@ -195,16 +197,21 @@ |
195 | 197 |
* @return {@code user}가 {@code resource}에 {@code operation}을 |
196 | 198 |
* 하는 것이 허용되는지의 여부 |
197 | 199 |
*/ |
198 |
- public static boolean isAllowed(User user, Resource resource, Operation operation) { |
|
200 |
+ public static boolean isAllowed(User user, Resource resource, Operation operation) |
|
201 |
+ throws IllegalStateException { |
|
199 | 202 |
if (user.isSiteManager()) { |
200 | 203 |
return true; |
201 | 204 |
} |
202 | 205 |
|
203 |
- Project project = resource.getProject(); |
|
204 |
- |
|
205 |
- if (project == null) { |
|
206 |
- return isGlobalResourceAllowed(user, resource, operation); |
|
206 |
+ if (resource instanceof GlobalResource) { |
|
207 |
+ return isGlobalResourceAllowed(user, (GlobalResource) resource, operation); |
|
207 | 208 |
} else { |
209 |
+ Project project = resource.getProject(); |
|
210 |
+ |
|
211 |
+ if (project == null) { |
|
212 |
+ throw new IllegalStateException("A project resource lost its project"); |
|
213 |
+ } |
|
214 |
+ |
|
208 | 215 |
return isProjectResourceAllowed(user, project, resource, operation); |
209 | 216 |
} |
210 | 217 |
} |
--- app/views/board/partial_list.scala.html
+++ app/views/board/partial_list.scala.html
... | ... | @@ -1,6 +1,6 @@ |
1 | 1 |
@(post:models.Posting, project:Project) |
2 | 2 |
<li class="board"> |
3 |
- <div class="num"> |
|
3 |
+ <div class="board-id"> |
|
4 | 4 |
<a href="@routes.BoardApp.post(project.owner, project.name, post.getNumber)">@post.getNumber</a> |
5 | 5 |
</div> |
6 | 6 |
<div class="author-avatar-space"> |
--- app/views/code/diff.scala.html
+++ app/views/code/diff.scala.html
... | ... | @@ -1,4 +1,4 @@ |
1 |
-@(project: Project, commit:playRepository.Commit, parentCommit:playRepository.Commit, comments:List[CommitComment], selectedBranch:String, diff: List[playRepository.FileDiff]) |
|
1 |
+@(project: Project, commit:playRepository.Commit, parentCommit:playRepository.Commit, comments:List[CommitComment], selectedBranch:String, diff: List[playRepository.FileDiff],path:String) |
|
2 | 2 |
|
3 | 3 |
@import playRepository.RepositoryService |
4 | 4 |
@import java.net.URLEncoder |
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 |
<div class="code-browse-wrap"> |
15 | 15 |
<div id="branches" class="btn-group branches pull-right" data-name="branch" data-activate="manual"> |
16 | 16 |
<button class="btn dropdown-toggle large" data-toggle="dropdown"> |
17 |
- <span class="d-label">@if(selectedBranch){ @selectedBranch } else { HEAD }</span> |
|
17 |
+ <span class="d-label">@selectedBranch</span> |
|
18 | 18 |
<span class="d-caret"><span class="caret"></span></span> |
19 | 19 |
</button> |
20 | 20 |
<ul class="dropdown-menu"> |
... | ... | @@ -129,7 +129,7 @@ |
129 | 129 |
|
130 | 130 |
<button id="watch-button" type="button" class="ybtn @if(commit.getWatchers(project).contains(UserApp.currentUser())) { active ybtn-watching }" data-toggle="button">@Messages("notification.watch")</button> |
131 | 131 |
|
132 |
- <a href="javascript: history.back();" class="ybtn pull-right">@Messages("button.list")</a> |
|
132 |
+ <a href="@routes.CodeHistoryApp.history(project.owner, project.name, selectedBranch, path)" class="ybtn pull-right">@Messages("button.list")</a> |
|
133 | 133 |
|
134 | 134 |
<div id="minimap" class="minimap-outer"> |
135 | 135 |
<div class="minimap-wrap"> |
--- app/views/code/history.scala.html
+++ app/views/code/history.scala.html
... | ... | @@ -22,9 +22,13 @@ |
22 | 22 |
routes.CodeHistoryApp.historyUntilHead(project.owner, project.name) |
23 | 23 |
} |
24 | 24 |
} |
25 |
-@getShowCommitURL(project:Project, commit:playRepository.Commit) = @{ |
|
25 |
+@getShowCommitURL(project:Project, commit:playRepository.Commit, path:String) = @{ |
|
26 | 26 |
if(selectedBranch){ |
27 |
- routes.CodeHistoryApp.show(project.owner, project.name, commit.getId()) + "?branch=" + URLEncoder.encode(selectedBranch, "UTF-8") |
|
27 |
+ var queryString = "?branch=" + URLEncoder.encode(selectedBranch, "UTF-8"); |
|
28 |
+ if(path != null) { |
|
29 |
+ queryString += "&path=" + path; |
|
30 |
+ } |
|
31 |
+ routes.CodeHistoryApp.show(project.owner, project.name, commit.getId()) + queryString; |
|
28 | 32 |
} else { |
29 | 33 |
routes.CodeHistoryApp.show(project.owner, project.name, commit.getId()) |
30 | 34 |
} |
... | ... | @@ -105,15 +109,15 @@ |
105 | 109 |
</thead> |
106 | 110 |
<tbody class="tbody"> |
107 | 111 |
@for(commit <- history.iterator()) { |
108 |
- @defining(getShowCommitURL(project, commit)){ showCommitURL => |
|
112 |
+ @defining(getShowCommitURL(project, commit, path)){ showCommitURL => |
|
109 | 113 |
<tr> |
110 | 114 |
<td class="commit-id"> |
111 |
- <a href="@showCommitURL#@path" title="@Messages("code.showCommit")"> |
|
115 |
+ <a href="@showCommitURL" title="@Messages("code.showCommit")"> |
|
112 | 116 |
@commit.getShortId() |
113 | 117 |
</a> |
114 | 118 |
</td> |
115 | 119 |
<td class="messages"> |
116 |
- @defining(CommitComment.count(project, commit.getId, if(path != null){"/"+path}else{null})){ numOfComment => |
|
120 |
+ @defining(CommitComment.count(project, commit.getId, path)){ numOfComment => |
|
117 | 121 |
@if(numOfComment > 0) { |
118 | 122 |
<span class="number-of-comments"><i class="yobicon-comments"></i> @numOfComment</span> |
119 | 123 |
} |
... | ... | @@ -123,7 +127,7 @@ |
123 | 127 |
@if(commitMsg.startsWith("Merge pull request")){ |
124 | 128 |
@defining(commitMsg.split(" ")(3)) { pullRequestIdPart => |
125 | 129 |
@defining(pullRequestIdPart.replace("#", "").toLong) { pullRequestId => |
126 |
- <a href="@showCommitURL#@path"> |
|
130 |
+ <a href="@showCommitURL"> |
|
127 | 131 |
@defining(commitMsg.indexOf(" #")) { indexOfPullRequestStart => |
128 | 132 |
@commitMsg.split("\n")(0).substring(0, indexOfPullRequestStart) |
129 | 133 |
} |
... | ... | @@ -131,7 +135,7 @@ |
131 | 135 |
<a href="@routes.PullRequestApp.pullRequest(project.owner, project.name, pullRequestId)" class="secondary-txt"> |
132 | 136 |
#@pullRequestId |
133 | 137 |
</a> |
134 |
- <a href="@showCommitURL#@path"> |
|
138 |
+ <a href="@showCommitURL"> |
|
135 | 139 |
@defining(commitMsg.indexOf(commitMsg.split(" ")(3)) + commitMsg.split(" ")(3).length) { indexOfPullRequestIdEnd => |
136 | 140 |
@commitMsg.split("\n")(0).substring(indexOfPullRequestIdEnd) |
137 | 141 |
} |
... | ... | @@ -139,7 +143,7 @@ |
139 | 143 |
} |
140 | 144 |
} |
141 | 145 |
} else { |
142 |
- <a href="@showCommitURL#@path">@commitMsg.split("\n")(0)</a> |
|
146 |
+ <a href="@showCommitURL">@commitMsg.split("\n")(0)</a> |
|
143 | 147 |
} |
144 | 148 |
|
145 | 149 |
@if(commitMsg.split("\n").length > 1){ |
--- app/views/code/svnDiff.scala.html
+++ app/views/code/svnDiff.scala.html
... | ... | @@ -1,4 +1,4 @@ |
1 |
-@(project: Project, commit:playRepository.Commit, parentCommit:playRepository.Commit, patch: String, comments:List[CommitComment], selectedBranch:String) |
|
1 |
+@(project: Project, commit:playRepository.Commit, parentCommit:playRepository.Commit, patch: String, comments:List[CommitComment], selectedBranch:String, path:String) |
|
2 | 2 |
|
3 | 3 |
@import playRepository.RepositoryService |
4 | 4 |
@import java.net.URLEncoder |
... | ... | @@ -91,7 +91,7 @@ |
91 | 91 |
</p> |
92 | 92 |
<pre class="commitMsg">@commit.getMessage</pre> |
93 | 93 |
<div class="diff-wrap"> |
94 |
- <div id="commit" class="diff-body show-comments">@patch</div> |
|
94 |
+ <div id="commit" data-commit-origin="true" class="diff-body show-comments hide">@patch</div> |
|
95 | 95 |
</div> |
96 | 96 |
<div id="compare" class="modal hide compare-wrap" tabindex="-1" role="dialog"> |
97 | 97 |
<h4 class="path"> |
... | ... | @@ -148,7 +148,7 @@ |
148 | 148 |
|
149 | 149 |
<button id="watch-button" type="button" class="ybtn @if(commit.getWatchers(project).contains(UserApp.currentUser())) { active }" data-toggle="button">@Messages("notification.watch")</button> |
150 | 150 |
|
151 |
- <a href="javascript: history.back();" class="ybtn pull-right">@Messages("button.list")</a> |
|
151 |
+ <a href="@routes.CodeHistoryApp.history(project.owner, project.name, selectedBranch, path)" class="ybtn pull-right">@Messages("button.list")</a> |
|
152 | 152 |
|
153 | 153 |
<div id="minimap" class="minimap-outer"> |
154 | 154 |
<div class="minimap-wrap"> |
--- app/views/common/commentForm.scala.html
+++ app/views/common/commentForm.scala.html
... | ... | @@ -16,11 +16,32 @@ |
16 | 16 |
} |
17 | 17 |
@** end of fileUploader **@ |
18 | 18 |
<div class="right-txt"> |
19 |
- <button class="ybtn ybtn-success">@Messages("button.comment.new")</button> |
|
19 |
+ <button type="submit" class="ybtn ybtn-success">@Messages("button.comment.new")</button> |
|
20 | 20 |
</div> |
21 | 21 |
</div> |
22 | 22 |
</div> |
23 | 23 |
</form> |
24 |
+ <script type="text/javascript"> |
|
25 |
+ $(document).ready(function(){ |
|
26 |
+ var welForm = $("#comment-form"); |
|
27 |
+ var welBtnSubmit = welForm.find("button[type=submit]"); |
|
28 |
+ |
|
29 |
+ welForm.on("submit", function(){ |
|
30 |
+ // set submit button as disabled |
|
31 |
+ welBtnSubmit.attr("disabled", "disabled").addClass("ybtn-disabled"); |
|
32 |
+ |
|
33 |
+ // restore button if cancel submitting with ESC key |
|
34 |
+ if(!welForm.data("cancelerAttached")){ |
|
35 |
+ welForm.data("cancelerAttached", true); |
|
36 |
+ $(window).on("keydown", function(weEvt){ |
|
37 |
+ if(weEvt.keyCode === 27){ |
|
38 |
+ welBtnSubmit.removeAttr("disabled").removeClass("ybtn-disabled"); |
|
39 |
+ } |
|
40 |
+ }); |
|
41 |
+ } |
|
42 |
+ }); |
|
43 |
+ }); |
|
44 |
+ </script> |
|
24 | 45 |
|
25 | 46 |
} else { |
26 | 47 |
|
--- app/views/git/edit.scala.html
+++ app/views/git/edit.scala.html
... | ... | @@ -105,7 +105,7 @@ |
105 | 105 |
@helper.inputText(form("title"), 'class->"text title", 'maxlength -> "250", 'tabindex -> 1, 'placeholder->"Title") |
106 | 106 |
@helper.textarea(form("body"), 'markdown -> true, 'class->"text content", 'tabindex -> 2) |
107 | 107 |
|
108 |
- @common.fileUploader(ResourceType.PULL_REQUEST, null) |
|
108 |
+ @common.fileUploader(ResourceType.PULL_REQUEST, pull.id) |
|
109 | 109 |
|
110 | 110 |
<div class="actions"> |
111 | 111 |
<button type="submit" class="ybtn ybtn-info">@Messages("button.save")</button> |
--- app/views/git/list.scala.html
+++ app/views/git/list.scala.html
... | ... | @@ -1,4 +1,5 @@ |
1 | 1 |
@(project: Project, page: com.avaje.ebean.Page[PullRequest], requestType: String) |
2 |
+@import utils.AccessControl |
|
2 | 3 |
|
3 | 4 |
@projectLayout(Messages("menu.pullRequest"), project, utils.MenuType.PULL_REQUEST) { |
4 | 5 |
<div class="page"> |
... | ... | @@ -11,10 +12,20 @@ |
11 | 12 |
@Messages("pullRequest") |
12 | 13 |
</a> |
13 | 14 |
} |
15 |
+ |
|
16 |
+ @** 이 프로젝트가 복사본이 아니며, 현재 사용자가 복사본을 갖고 있고, 코드보내기 권한이 있는 경우 **@ |
|
17 |
+ @defining(Project.findByOwnerAndOriginalProject(UserApp.currentUser().loginId, project)){ myFork => |
|
18 |
+ @if(!project.isFork && myFork != null && AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.PULL_REQUEST)){ |
|
19 |
+ <a href="@routes.PullRequestApp.newPullRequestForm(myFork.owner, myFork.name)" class="ybtn ybtn-success"> |
|
20 |
+ <i class="yobicon-split yobicon-large"></i> |
|
21 |
+ @Messages("pullRequest.toHere") |
|
22 |
+ </a> |
|
23 |
+ } |
|
24 |
+ } |
|
14 | 25 |
</div> |
15 | 26 |
|
16 | 27 |
@if(project.hasForks() || project.isFork()) { |
17 |
- <ul class="nav nav-tabs cb"> |
|
28 |
+ <ul class="nav nav-tabs"> |
|
18 | 29 |
@if(project.hasForks()){ |
19 | 30 |
<li @if(requestType.equals("opened")){class="active"}> |
20 | 31 |
<a href="@routes.PullRequestApp.pullRequests(project.owner, project.name)"> |
--- app/views/git/partial_diff.scala.html
+++ app/views/git/partial_diff.scala.html
... | ... | @@ -25,121 +25,120 @@ |
25 | 25 |
} |
26 | 26 |
} |
27 | 27 |
|
28 |
- @helper.inputText(form("title"), 'class->"text title", 'maxlength -> "250", 'tabindex -> 1) |
|
29 |
- @helper.textarea(form("body"), 'markdown -> true, 'class->"text content", 'tabindex -> 2) |
|
28 |
+@helper.inputText(form("title"), 'class->"text title", 'maxlength -> "250", 'tabindex -> 1) |
|
29 |
+@helper.textarea(form("body"), 'markdown -> true, 'class->"text content", 'tabindex -> 2) |
|
30 | 30 |
|
31 |
- @common.fileUploader(ResourceType.PULL_REQUEST, null) |
|
31 |
+@common.fileUploader(ResourceType.PULL_REQUEST, null) |
|
32 |
+@common.markdown(project) |
|
32 | 33 |
|
33 |
- @common.markdown(project) |
|
34 |
- |
|
35 |
- <div class="actions"> |
|
36 |
- <button type="submit" class="ybtn ybtn-success">@Messages("button.save")</button> |
|
37 |
- <a href="javascript:history.back();" class="ybtn">@Messages("button.cancel")</a> |
|
34 |
+<div class="actions"> |
|
35 |
+ <button type="submit" class="ybtn ybtn-success">@Messages("button.save")</button> |
|
36 |
+ <a href="javascript:history.back();" class="ybtn">@Messages("button.cancel")</a> |
|
37 |
+</div> |
|
38 |
+ |
|
39 |
+<div id="spin" style="position: absolute; top:50%; left:50%"></div> |
|
40 |
+ |
|
41 |
+<div id="diff"> |
|
42 |
+@if(result != null) { |
|
43 |
+ @if(result.getGitCommits().isEmpty()) { |
|
44 |
+ <h4>@Messages("pullRequest.diff.noChanges")</h4> |
|
45 |
+ } else { |
|
46 |
+ <div style="margin-top:20px;"> |
|
47 |
+ @if(result.getGitConflicts() == null){ |
|
48 |
+ <div class="alert alert-success"> |
|
49 |
+ <h5>@Messages("pullRequest.is.safe")</h5> |
|
38 | 50 |
</div> |
39 |
- |
|
40 |
- <div id="spin" style="position: absolute; top:50%; left:50%"></div> |
|
41 |
- |
|
42 |
- <div id="diff"> |
|
43 |
- @if(result != null) { |
|
44 |
- @if(result.getGitCommits().isEmpty()) { |
|
45 |
- <h4>@Messages("pullRequest.diff.noChanges")</h4> |
|
46 |
- } else { |
|
47 |
- <div style="margin-top:20px;"> |
|
48 |
- @if(result.getGitConflicts() == null){ |
|
49 |
- <div class="alert alert-success"> |
|
50 |
- <h5>@Messages("pullRequest.is.safe")</h5> |
|
51 |
- </div> |
|
52 |
- } else { |
|
53 |
- <div class="alert alert-error"> |
|
54 |
- <h5>@Messages("pullRequest.is.not.safe")</h5> |
|
55 |
- </div> |
|
56 |
- } |
|
57 |
- </div> |
|
58 |
- |
|
59 |
- <ul class="nav nav-tabs nm"> |
|
51 |
+ } else { |
|
52 |
+ <div class="alert alert-error"> |
|
53 |
+ <h5>@Messages("pullRequest.is.not.safe")</h5> |
|
54 |
+ </div> |
|
55 |
+ } |
|
56 |
+ </div> |
|
57 |
+ |
|
58 |
+ <ul class="nav nav-tabs nm"> |
|
60 | 59 |
<li class="active"><a href="#__commits" data-toggle="tab">@Messages("pullRequest.menu.commit")</a></li> |
61 | 60 |
<li><a href="#__changes" data-toggle="tab">@Messages("pullRequest.menu.changes")</a></li> |
62 | 61 |
</ul> |
63 |
- <div class="tab-content"> |
|
64 |
- <div id="__commits" class="code-browse-wrap tab-pane active"> |
|
65 |
- <div id="history" class="commit-wrap mt20"> |
|
66 |
- <table class="code-table commits"> |
|
67 |
- <thead class="thead"> |
|
68 |
- <tr> |
|
69 |
- <td class="commit-id"><strong>@{"@"}</strong></td> |
|
70 |
- <td class="messages"><strong>@Messages("code.commitMsg")</strong></td> |
|
71 |
- <td class="date"><strong>@Messages("code.commitDate")</strong></td> |
|
72 |
- <td class="author"><strong>@Messages("code.author")</strong></td> |
|
73 |
- </tr> |
|
74 |
- </thead> |
|
75 |
- <tbody class="tbody"> |
|
76 |
- @for(commit <- result.getGitCommits()) { |
|
77 |
- <tr> |
|
78 |
- <td class="commit-id"> |
|
79 |
- <a href="@routes.CodeHistoryApp.show(pullRequest.fromProject.owner, pullRequest.fromProject.name, commit.getId())"> |
|
80 |
- @commit.getShortId() |
|
81 |
- <i class="yobicon-right"></i> |
|
82 |
- </a> |
|
83 |
- </td> |
|
84 |
- |
|
85 |
- <td class="messages"> |
|
86 |
- @defining(CommitComment.count(pullRequest.fromProject, commit.getId, null)){ numOfComment => |
|
87 |
- @if(numOfComment > 0) { |
|
88 |
- <span class="number-of-comments"><i class="yobicon-comments"></i> @numOfComment</span> |
|
89 |
- } |
|
90 |
- } |
|
91 |
- |
|
92 |
- @defining(commit.getMessage()){ commitMsg => |
|
93 |
- <a href="@routes.CodeHistoryApp.show(pullRequest.fromProject.owner, pullRequest.fromProject.name, commit.getId())"> |
|
94 |
- @commitMsg.split("\n")(0) |
|
95 |
- </a> |
|
96 |
- @if(commitMsg.split("\n").length > 1){ |
|
97 |
- <button type="button" class="more"><i class="yobicon-ellipsis-horizontal"></i></button> |
|
98 |
- <pre class="hidden">@commitMsg.replace(commitMsg.split("\n")(0)+"\n", "")</pre> |
|
99 |
- } |
|
100 |
- } |
|
101 |
- </td> |
|
102 |
- <td class="date">@agoString(ago(commit.getAuthorDate()))</td> |
|
103 |
- <td class="author @commit.getAuthorEmail"> |
|
104 |
- @defining(User.find.where.eq("email", commit.getAuthorEmail).findUnique) { user => |
|
105 |
- @if(user != null) { |
|
106 |
- <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap"> |
|
107 |
- <img src="@user.avatarUrl" alt="@user.name" width="32" height="32"/> |
|
108 |
- </a> |
|
109 |
- } else { |
|
110 |
- <div class="avatar-wrap"> |
|
111 |
- <img src="@urlToPicture(commit.getAuthorEmail(), 32)" width="32" height="32"/> |
|
112 |
- </div> |
|
113 |
- } |
|
114 |
- } |
|
115 |
- </td> |
|
116 |
- </tr> |
|
117 |
- } |
|
118 |
- </tbody> |
|
119 |
- </table> |
|
120 |
- </div> |
|
121 |
- </div> |
|
122 |
- |
|
123 |
- <div id="__changes" class="tab-pane"> |
|
124 |
- <div class="diff-body"> |
|
125 |
- @views.html.partial_diff(pullRequest.getDiff) |
|
126 |
- </div> |
|
127 |
- </div> |
|
128 |
- </div> |
|
129 |
- } |
|
130 |
- } |
|
131 |
- </div> |
|
132 |
- <input type="hidden" id="commitChanged" value="@if(result != null){ @result.commitChanged } else {false}" /> |
|
133 |
- <script type="text/javascript"> |
|
134 |
- $(document).ready(function() { |
|
135 |
- $yobi.loadModule("code.Diff", { |
|
136 |
- "welDiff": $("#pull-request-changes"), |
|
137 |
- "sAttachmentAction": "@routes.AttachmentApp.uploadFile", |
|
138 |
- "bCommentable": false, |
|
139 |
- "sTplFileURLA" : "@routes.CodeApp.codeBrowserWithBranch(pullRequest.toProject.owner, pullRequest.toProject.name, "${commitId}", "${path}")", |
|
140 |
- "sTplFileURLB" : "@routes.CodeApp.codeBrowserWithBranch(pullRequest.fromProject.owner, pullRequest.fromProject.name, "${commitId}", "${path}")", |
|
141 |
- "sTplRawURLA" : "@routes.CodeApp.showRawFile(pullRequest.toProject.owner, pullRequest.toProject.name, "${commitId}", "${path}")", |
|
142 |
- "sTplRawURLB" : "@routes.CodeApp.showRawFile(pullRequest.fromProject.owner, pullRequest.fromProject.name, "${commitId}", "${path}")" |
|
143 |
- }); |
|
144 |
- }); |
|
145 |
- </script>(No newline at end of file) |
|
62 |
+ <div class="tab-content"> |
|
63 |
+ <div id="__commits" class="code-browse-wrap tab-pane active"> |
|
64 |
+ <div id="history" class="commit-wrap mt20"> |
|
65 |
+ <table class="code-table commits"> |
|
66 |
+ <thead class="thead"> |
|
67 |
+ <tr> |
|
68 |
+ <td class="commit-id"><strong>@{"@"}</strong></td> |
|
69 |
+ <td class="messages"><strong>@Messages("code.commitMsg")</strong></td> |
|
70 |
+ <td class="date"><strong>@Messages("code.commitDate")</strong></td> |
|
71 |
+ <td class="author"><strong>@Messages("code.author")</strong></td> |
|
72 |
+ </tr> |
|
73 |
+ </thead> |
|
74 |
+ <tbody class="tbody"> |
|
75 |
+ @for(commit <- result.getGitCommits()) { |
|
76 |
+ <tr> |
|
77 |
+ <td class="commit-id"> |
|
78 |
+ <a href="@routes.CodeHistoryApp.show(pullRequest.fromProject.owner, pullRequest.fromProject.name, commit.getId())"> |
|
79 |
+ @commit.getShortId() |
|
80 |
+ <i class="yobicon-right"></i> |
|
81 |
+ </a> |
|
82 |
+ </td> |
|
83 |
+ |
|
84 |
+ <td class="messages"> |
|
85 |
+ @defining(CommitComment.count(pullRequest.fromProject, commit.getId, null)){ numOfComment => |
|
86 |
+ @if(numOfComment > 0) { |
|
87 |
+ <span class="number-of-comments"><i class="yobicon-comments"></i> @numOfComment</span> |
|
88 |
+ } |
|
89 |
+ } |
|
90 |
+ |
|
91 |
+ @defining(commit.getMessage()){ commitMsg => |
|
92 |
+ <a href="@routes.CodeHistoryApp.show(pullRequest.fromProject.owner, pullRequest.fromProject.name, commit.getId())"> |
|
93 |
+ @commitMsg.split("\n")(0) |
|
94 |
+ </a> |
|
95 |
+ @if(commitMsg.split("\n").length > 1){ |
|
96 |
+ <button type="button" class="more"><i class="yobicon-ellipsis-horizontal"></i></button> |
|
97 |
+ <pre class="hidden">@commitMsg.replace(commitMsg.split("\n")(0)+"\n", "")</pre> |
|
98 |
+ } |
|
99 |
+ } |
|
100 |
+ </td> |
|
101 |
+ <td class="date">@agoString(ago(commit.getAuthorDate()))</td> |
|
102 |
+ <td class="author @commit.getAuthorEmail"> |
|
103 |
+ @defining(User.find.where.eq("email", commit.getAuthorEmail).findUnique) { user => |
|
104 |
+ @if(user != null) { |
|
105 |
+ <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap"> |
|
106 |
+ <img src="@user.avatarUrl" alt="@user.name" width="32" height="32"/> |
|
107 |
+ </a> |
|
108 |
+ } else { |
|
109 |
+ <div class="avatar-wrap"> |
|
110 |
+ <img src="@urlToPicture(commit.getAuthorEmail(), 32)" width="32" height="32"/> |
|
111 |
+ </div> |
|
112 |
+ } |
|
113 |
+ } |
|
114 |
+ </td> |
|
115 |
+ </tr> |
|
116 |
+ } |
|
117 |
+ </tbody> |
|
118 |
+ </table> |
|
119 |
+ </div> |
|
120 |
+ </div> |
|
121 |
+ |
|
122 |
+ <div id="__changes" class="tab-pane"> |
|
123 |
+ <div class="diff-body"> |
|
124 |
+ @views.html.partial_diff(pullRequest.getDiff) |
|
125 |
+ </div> |
|
126 |
+ </div> |
|
127 |
+ </div> |
|
128 |
+ } |
|
129 |
+} |
|
130 |
+</div> |
|
131 |
+<input type="hidden" id="commitChanged" value="@if(result != null){ @result.commitChanged } else {false}" /> |
|
132 |
+<script type="text/javascript"> |
|
133 |
+$(document).ready(function() { |
|
134 |
+ $yobi.loadModule("code.Diff", { |
|
135 |
+ "welDiff" : $("#pull-request-changes"), |
|
136 |
+ "bCommentable": false, |
|
137 |
+ "bUseUploader": false, |
|
138 |
+ "sTplFileURLA": "@routes.CodeApp.codeBrowserWithBranch(pullRequest.toProject.owner, pullRequest.toProject.name, "${commitId}", "${path}")", |
|
139 |
+ "sTplFileURLB": "@routes.CodeApp.codeBrowserWithBranch(pullRequest.fromProject.owner, pullRequest.fromProject.name, "${commitId}", "${path}")", |
|
140 |
+ "sTplRawURLA" : "@routes.CodeApp.showRawFile(pullRequest.toProject.owner, pullRequest.toProject.name, "${commitId}", "${path}")", |
|
141 |
+ "sTplRawURLB" : "@routes.CodeApp.showRawFile(pullRequest.fromProject.owner, pullRequest.fromProject.name, "${commitId}", "${path}")" |
|
142 |
+ }); |
|
143 |
+}); |
|
144 |
+</script>(No newline at end of file) |
--- conf/messages
+++ conf/messages
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 |
app.restart.notice = The server needs to be restarted. |
27 | 27 |
app.restart.welcome = Welcome! |
28 | 28 |
app.secret.notice = This form is to reset the Secret key.<br>Submitting seed generates random Secret key based the seed.<br>Feel free to submit long and complex value. You don't need to remember it. |
29 |
-app.secret.warning.title = The Secret key MUST be secret. |
|
29 |
+app.secret.warning.title = The Secret key MUST be secret. |
|
30 | 30 |
app.secret.warning.desc = If a bad guy knows the secret, He can login as any user of your site! |
31 | 31 |
app.secret.welcome = Welcome to {0}! |
32 | 32 |
app.title = Collaborative Software Development Platform |
... | ... | @@ -233,7 +233,7 @@ |
233 | 233 |
issue.state.enrolled = Enrolled |
234 | 234 |
issue.state.finished = Finished |
235 | 235 |
issue.state.open = Open |
236 |
-issue.state.rejected = Rejected |
|
236 |
+issue.state.rejected = Postponed |
|
237 | 237 |
issue.state.solved = Solved |
238 | 238 |
issue.unwatch.start = Notifications of this issue has muted |
239 | 239 |
issue.update.assignee = Update assignee |
... | ... | @@ -459,7 +459,7 @@ |
459 | 459 |
pullRequest.help.message.2 = Please select your branch that contains your code to send and original project's branch to receive your code, and explain what you have done. |
460 | 460 |
pullRequest.help.message.3 = The member of the original project can accept your code or reject. |
461 | 461 |
pullRequest.is.empty = There are no pull requests |
462 |
-pullRequest.is.merging = Checking whether code is safety. Please wait for a while to complete. |
|
462 |
+pullRequest.is.merging = Checking whether code is safety. Please wait for a while to complete. |
|
463 | 463 |
pullRequest.is.not.safe = This pull request can not be merged safely, There may be some conflicts. |
464 | 464 |
pullRequest.is.safe = This pull request can be merged safely. |
465 | 465 |
pullRequest.listEmpty = No request received yet. |
... | ... | @@ -495,12 +495,13 @@ |
495 | 495 |
pullRequest.title.required = Input title. |
496 | 496 |
pullRequest.to = To |
497 | 497 |
pullRequest.toBranch.required = Select a branch that will receives the sending code. |
498 |
+pullRequest.toHere = New PullRequest |
|
498 | 499 |
site = Site |
499 | 500 |
site.features.codeManagement = All your codes are stored in a version controlled system safely. |
500 | 501 |
site.features.codeReview = You can review all changes on code with your team before merging. Discussion makes your code better. |
501 | 502 |
site.features.issueTracker = Yobi provides an issue tracker to make you deal with your issues more easily and clearly. |
502 | 503 |
site.features.privateRepositories = Everyone has secrets. You can keep your secret codes at your private repositories. |
503 |
-site.features.unlimitedProjects = You can create repositories as many as you want. Just create it. |
|
504 |
+site.features.unlimitedProjects = You can create repositories as many as you want. Just create it. |
|
504 | 505 |
site.features.workTeam = You can make a team for your project with simple and easy team management tools of Yobi. |
505 | 506 |
site.mail.authMethod = Authentication method |
506 | 507 |
site.mail.body = Body |
--- conf/messages.ja
+++ conf/messages.ja
... | ... | @@ -496,6 +496,7 @@ |
496 | 496 |
pullRequest.title.required = タイトルを入力してください |
497 | 497 |
pullRequest.to = コード 受ける場所 |
498 | 498 |
pullRequest.toBranch.required = コードを受けてもらいたいブランチを選んでください |
499 |
+pullRequest.toHere = こちらへプルリクエスト |
|
499 | 500 |
site = サイト |
500 | 501 |
site.features.codeManagement = All your codes are stored in a version controlled system safely. |
501 | 502 |
site.features.codeReview = You can review all changes on code with your team before merging. Discussion makes your code better. |
--- conf/messages.ko
+++ conf/messages.ko
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 |
app.restart.notice = 서버를 재시작해야합니다. |
27 | 27 |
app.restart.welcome = 환영합니다! |
28 | 28 |
app.secret.notice = 이 폼은 사이트 비밀값을 생성하는 폼입니다.<br>임의의 문자열을 입력하시면 그 문자열을 시드로 하여 무작위로 비밀값을 생성합니다.<br>기억할 필요가 없으므로, 길고 복잡한 값을 입력하셔도 됩니다. |
29 |
-app.secret.warning.title = 사이트 비밀값은 사이트 관리자외의 누구도 알아서는 안됩니다. |
|
29 |
+app.secret.warning.title = 사이트 비밀값은 사이트 관리자외의 누구도 알아서는 안됩니다. |
|
30 | 30 |
app.secret.warning.desc = 사이트 비밀값을 알고 있는 사람은 이 사이트의 어떠한 사용자 계정으로도 로그인을 할 수 있습니다! |
31 | 31 |
app.secret.welcome = {0}가 처음으로 시작되려는 순간입니다! (두둥!) |
32 | 32 |
app.title = 협업개발 플랫폼 |
... | ... | @@ -298,7 +298,7 @@ |
298 | 298 |
notification.none = 알림 메시지가 없습니다. |
299 | 299 |
notification.pullrequest.closed = 보낸 코드가 반영됨(merged) |
300 | 300 |
notification.pullrequest.conflicts = 충돌이 발생 |
301 |
-notification.pullrequest.rejected = 보낸 코드 거절 |
|
301 |
+notification.pullrequest.rejected = 보낸 코드 보류 |
|
302 | 302 |
notification.pullrequest.reopened = 코드 주고받기 다시 열림 |
303 | 303 |
notification.type.issue.assignee.changed = 이슈 담당자 변경 |
304 | 304 |
notification.type.issue.state.changed = 이슈 상태 변경 |
... | ... | @@ -313,7 +313,7 @@ |
313 | 313 |
notification.type.pullrequest.conflicts = 코드보내기 충돌 |
314 | 314 |
notification.type.pullrequest.merged = 코드보내기 반영됨(merged) |
315 | 315 |
notification.type.pullrequest.merged.conflict = 코드보내기 충돌 |
316 |
-notification.type.pullrequest.merged.resolved = 코드보내기 충돌 해결 |
|
316 |
+notification.type.pullrequest.merged.resolved = 코드보내기 충돌 해결 |
|
317 | 317 |
notification.type.pullrequest.state.changed = 코드보내기 상태 변경 |
318 | 318 |
notification.watch = 지켜보기 |
319 | 319 |
notification.will.help = 프로젝트를 지켜보면 다음 이벤트가 발생할 때 알림 메시지를 받습니다. |
... | ... | @@ -496,6 +496,7 @@ |
496 | 496 |
pullRequest.title.required = 제목을 입력하세요. |
497 | 497 |
pullRequest.to = 코드 받을 곳 |
498 | 498 |
pullRequest.toBranch.required = 코드를 받을 브랜치를 선택하세요. |
499 |
+pullRequest.toHere = 이 프로젝트에 코드 보내기 |
|
499 | 500 |
site = 사이트 |
500 | 501 |
site.features.codeManagement = 작성한 코드는 모두 이력이 관리되는 형태로 안전하게 서버에 보관됩니다. |
501 | 502 |
site.features.codeReview = 변경된 코드를 보면서 팀원들과 토론해보세요. 코드의 완성도를 더욱 높일 수 있습니다. |
--- public/javascripts/common/yobi.Files.js
+++ public/javascripts/common/yobi.Files.js
... | ... | @@ -292,6 +292,7 @@ |
292 | 292 |
* |
293 | 293 |
* @param {HTMLElement} elContainer |
294 | 294 |
* @param {HTMLTextareaElement} elTextarea (Optional) |
295 |
+ * @param {String} sNamespace |
|
295 | 296 |
* @return {Wrapped Element} |
296 | 297 |
*/ |
297 | 298 |
function _getUploader(elContainer, elTextarea, sNamespace){ |
... | ... | @@ -301,7 +302,7 @@ |
301 | 302 |
if($(elContainer).data("isYobiUploader") || $(elTextarea).data("isYobiUploader")){ |
302 | 303 |
return false; |
303 | 304 |
} |
304 |
- |
|
305 |
+ |
|
305 | 306 |
_initElement({ |
306 | 307 |
"elContainer": elContainer, |
307 | 308 |
"elTextarea" : elTextarea, |
... | ... | @@ -392,6 +393,8 @@ |
392 | 393 |
htElement.welInputFile.unbind(); |
393 | 394 |
htElement.welContainer.unbind(); |
394 | 395 |
htElement.welTextarea.unbind(); |
396 |
+ htElement.welContainer.data("isYobiUploader", false); |
|
397 |
+ htElement.welTextarea.data("isYobiUploader", false); |
|
395 | 398 |
} |
396 | 399 |
|
397 | 400 |
/** |
--- public/javascripts/service/yobi.board.Write.js
+++ public/javascripts/service/yobi.board.Write.js
... | ... | @@ -91,7 +91,7 @@ |
91 | 91 |
"elContainer" : htElement.welUploader, |
92 | 92 |
"elTextarea" : htElement.welTextarea, |
93 | 93 |
"sTplFileItem" : htVar.sTplFileItem, |
94 |
- "sUploaderId" : Uploader.attr("data-namespace") |
|
94 |
+ "sUploaderId" : oUploader.attr("data-namespace") |
|
95 | 95 |
})); |
96 | 96 |
} |
97 | 97 |
} |
--- public/javascripts/service/yobi.code.Diff.js
+++ public/javascripts/service/yobi.code.Diff.js
... | ... | @@ -24,7 +24,11 @@ |
24 | 24 |
_attachEvent(); |
25 | 25 |
_render(); |
26 | 26 |
|
27 |
- _initFileUploader(); |
|
27 |
+ // bUseUploader 를 명시적으로 false 로 지정한 경우 |
|
28 |
+ // code.Diff 에서는 파일업로더 초기화를 실행하지 않음 |
|
29 |
+ if(htVar.bUseUploader !== false){ |
|
30 |
+ _initFileUploader(); |
|
31 |
+ } |
|
28 | 32 |
_initFileDownloader(); |
29 | 33 |
_initToggleCommentsButton(); |
30 | 34 |
_initFileViewButton(); |
--- public/javascripts/service/yobi.code.SvnDiff.js
+++ public/javascripts/service/yobi.code.SvnDiff.js
... | ... | @@ -50,7 +50,7 @@ |
50 | 50 |
htVar.sTplMiniMapLink = '<a href="#${id}" style="top:${top}px; height:${height}px;"></a>'; |
51 | 51 |
|
52 | 52 |
// yobi.Attachments |
53 |
- htVar.sTplFileItem = ('#tplAttachedFile').text(); |
|
53 |
+ htVar.sTplFileItem = $('#tplAttachedFile').text(); |
|
54 | 54 |
} |
55 | 55 |
|
56 | 56 |
/** |
... | ... | @@ -134,6 +134,8 @@ |
134 | 134 |
window.scrollTo(0, welTarget.offset().top); |
135 | 135 |
} |
136 | 136 |
} |
137 |
+ |
|
138 |
+ $('[data-commit-origin="true"]').removeClass("hide"); |
|
137 | 139 |
} |
138 | 140 |
|
139 | 141 |
/** |
--- test/utils/AccessControlTest.java
+++ test/utils/AccessControlTest.java
... | ... | @@ -5,12 +5,14 @@ |
5 | 5 |
import org.junit.After; |
6 | 6 |
import org.junit.Before; |
7 | 7 |
import org.junit.Test; |
8 |
+import org.junit.Assert; |
|
8 | 9 |
|
9 | 10 |
import play.test.Helpers; |
10 | 11 |
|
11 | 12 |
import static org.fest.assertions.Assertions.assertThat; |
12 | 13 |
|
13 | 14 |
import models.enumeration.Operation; |
15 |
+import models.enumeration.State; |
|
14 | 16 |
|
15 | 17 |
public class AccessControlTest extends ModelTest<Role>{ |
16 | 18 |
@Before |
... | ... | @@ -74,4 +76,30 @@ |
74 | 76 |
assertThat(canUpdate).isEqualTo(false); |
75 | 77 |
assertThat(canDelete).isEqualTo(false); |
76 | 78 |
} |
79 |
+ |
|
80 |
+ // AccessControl.isAllowed throws IllegalStateException if the resource |
|
81 |
+ // belongs to a project but the project is missing. |
|
82 |
+ @Test |
|
83 |
+ public void isAllowed_lostProject() { |
|
84 |
+ // Given |
|
85 |
+ User author = User.findByLoginId("nori"); |
|
86 |
+ Project projectYobi = Project.findByOwnerAndProjectName("yobi", "projectYobi"); |
|
87 |
+ Issue issue = new Issue(); |
|
88 |
+ issue.setProject(projectYobi); |
|
89 |
+ issue.setTitle("hello"); |
|
90 |
+ issue.setBody("world"); |
|
91 |
+ issue.setAuthor(author); |
|
92 |
+ issue.state = State.OPEN; |
|
93 |
+ issue.save(); |
|
94 |
+ |
|
95 |
+ // When |
|
96 |
+ issue.project = null; |
|
97 |
+ |
|
98 |
+ // Then |
|
99 |
+ try { |
|
100 |
+ AccessControl.isAllowed(author, issue.asResource(), Operation.READ); |
|
101 |
+ Assert.fail(); |
|
102 |
+ } catch (IllegalStateException e) { |
|
103 |
+ } |
|
104 |
+ } |
|
77 | 105 |
} |
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?