├── README.md ├── app ├── views │ ├── tags │ │ ├── block │ │ │ ├── time.html │ │ │ ├── top-bar-user.html │ │ │ └── menu.html │ │ ├── user │ │ │ ├── name.html │ │ │ └── picture.html │ │ ├── document │ │ │ ├── list.html │ │ │ ├── description.html │ │ │ ├── title.html │ │ │ ├── preview.html │ │ │ ├── list-item.html │ │ │ └── stats.html │ │ ├── discussion │ │ │ ├── list.html │ │ │ ├── title.html │ │ │ ├── list-item.html │ │ │ └── stats.html │ │ ├── form │ │ │ ├── select.html │ │ │ ├── textarea.html │ │ │ ├── input.html │ │ │ └── field.html │ │ ├── vote │ │ │ ├── button.html │ │ │ └── scripts.html │ │ └── comment │ │ │ ├── list-item.html │ │ │ └── scripts.html │ ├── admin │ │ ├── Comments │ │ │ ├── blank.html │ │ │ ├── list.html │ │ │ └── show.html │ │ ├── Users │ │ │ ├── blank.html │ │ │ ├── list.html │ │ │ └── show.html │ │ ├── Documents │ │ │ ├── blank.html │ │ │ ├── list.html │ │ │ └── show.html │ │ ├── Discussions │ │ │ ├── blank.html │ │ │ ├── list.html │ │ │ └── show.html │ │ └── Categories │ │ │ ├── list.html │ │ │ ├── show.html │ │ │ └── blank.html │ ├── errors │ │ ├── 404.html │ │ └── 500.html │ ├── web │ │ ├── Documents │ │ │ ├── ajax_list.html │ │ │ ├── edit.html │ │ │ └── list.html │ │ ├── Discussions │ │ │ ├── ajax_list.html │ │ │ ├── edit.html │ │ │ ├── add.html │ │ │ └── list.html │ │ ├── Comments │ │ │ └── list.html │ │ ├── Users │ │ │ └── read.html │ │ └── WebController │ │ │ └── index.html │ ├── CRUD │ │ └── layout.html │ ├── web.html.bak │ └── web.html ├── jobs │ ├── Bootstrap.java │ ├── DeleteBackgroundJobStatusJob.java │ ├── IncrementDocumentCopyCountJob.java │ ├── IncrementDocumentReadCountJob.java │ ├── IncrementDocumentDownloadCountJob.java │ ├── UpdateDocumentCommentCountJob.java │ ├── FetchDocumentThumbnailJob.java │ └── CopyDocumentJob.java ├── models │ ├── BackgroundJobStatus.java │ ├── Thumbnail.java │ ├── DocumentJobStatus.java │ ├── UserRole.java │ ├── ExportLink.java │ ├── DiscussionDocument.java │ ├── dialects │ │ └── FullTextSearchPostgreSQLDialect.java │ ├── BaseModel.java │ ├── Category.java │ ├── enums │ │ └── Mime.java │ ├── User.java │ ├── Vote.java │ └── Comment.java ├── controllers │ ├── admin │ │ ├── Users.java │ │ ├── Comments.java │ │ ├── Documents.java │ │ ├── Categories.java │ │ └── Discussions.java │ ├── AdminController.java │ ├── api │ │ ├── DocumentJobsStatus.java │ │ ├── Categories.java │ │ ├── Comments.java │ │ ├── Votes.java │ │ ├── ApiController.java │ │ ├── DiscussionDocuments.java │ │ ├── Discussions.java │ │ └── Documents.java │ ├── web │ │ ├── Users.java │ │ ├── Comments.java │ │ ├── Documents.java │ │ ├── Discussions.java │ │ ├── WebController.java │ │ └── Auth.java │ ├── RolesHandler.java │ └── AppController.java ├── utils │ └── Labels.java └── services │ └── googleoauth │ ├── GoogleOAuthTokens.java │ ├── GoogleOAuthCredentialListener.java │ ├── GoogleUserInfo.java │ ├── GoogleOAuthConfig.java │ └── GoogleOAuth.java ├── public ├── images │ ├── doc.png │ ├── logo.png │ ├── user.png │ ├── favicon.png │ ├── logo-large.png │ ├── logo-medium.png │ └── hero-graphic.png ├── stylesheets │ ├── fonts │ │ ├── icomoon.eot │ │ ├── icomoon.ttf │ │ └── icomoon.woff │ └── icons.css └── javascripts │ ├── jquery.timeago.fr.js │ ├── jquery.timeago.en.js │ ├── app.js │ ├── jquery.cookie.js │ ├── bootstrap.button.js │ ├── jquery.placeholder.js │ └── jquery.timeago.js ├── test ├── data.yml ├── Application.test.html ├── BasicTest.java └── ApplicationTest.java ├── db └── evolutions │ ├── 5.sql │ ├── 7.sql │ ├── 2.sql │ ├── 3.sql │ ├── 4.sql │ ├── 8.sql │ ├── 6.sql │ └── 1.sql ├── conf ├── application.override.conf ├── dependencies.yml ├── routes └── messages.en └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | See http://www.opendocshub.org for help -------------------------------------------------------------------------------- /app/views/tags/block/time.html: -------------------------------------------------------------------------------- 1 | 2 | ${_time} 3 | -------------------------------------------------------------------------------- /app/views/tags/user/name.html: -------------------------------------------------------------------------------- 1 | 2 | ${_user} 3 | -------------------------------------------------------------------------------- /public/images/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/images/doc.png -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/images/logo.png -------------------------------------------------------------------------------- /public/images/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/images/user.png -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/images/favicon.png -------------------------------------------------------------------------------- /app/views/tags/document/list.html: -------------------------------------------------------------------------------- 1 | #{list _documents} 2 | #{document.list-item document : _ /} 3 | #{/list} -------------------------------------------------------------------------------- /public/images/logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/images/logo-large.png -------------------------------------------------------------------------------- /public/images/logo-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/images/logo-medium.png -------------------------------------------------------------------------------- /public/images/hero-graphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/images/hero-graphic.png -------------------------------------------------------------------------------- /app/views/tags/discussion/list.html: -------------------------------------------------------------------------------- 1 | #{list _discussions} 2 | #{discussion.list-item discussion : _ /} 3 | #{/list} 4 | 5 | -------------------------------------------------------------------------------- /public/stylesheets/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/stylesheets/fonts/icomoon.eot -------------------------------------------------------------------------------- /public/stylesheets/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/stylesheets/fonts/icomoon.ttf -------------------------------------------------------------------------------- /public/stylesheets/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angebagui/odh-web/master/public/stylesheets/fonts/icomoon.woff -------------------------------------------------------------------------------- /app/views/tags/discussion/title.html: -------------------------------------------------------------------------------- 1 | ${_discussion.title.toLowerCase()} -------------------------------------------------------------------------------- /test/data.yml: -------------------------------------------------------------------------------- 1 | # you describe your data using the YAML notation here 2 | # and then load them using Fixtures.load("data.yml") 3 | 4 | # User(bob): 5 | # email: bob@gmail.com 6 | # password: secret 7 | # fullname: Bob -------------------------------------------------------------------------------- /app/views/tags/document/description.html: -------------------------------------------------------------------------------- 1 |
Please add a comment through the frontend.
10 |Users have to register through the frontend.
10 |Please use the document upload form on the frontend.
10 |
7 | #{/else}
8 | #{if _showName}
9 | ${_user}
10 | #{/if}
11 |
--------------------------------------------------------------------------------
/app/jobs/DeleteBackgroundJobStatusJob.java:
--------------------------------------------------------------------------------
1 | package jobs;
2 |
3 | import java.util.Date;
4 |
5 | import models.DocumentJobStatus;
6 | import play.jobs.Every;
7 | import play.jobs.Job;
8 |
9 | @Every("1h")
10 | public class DeleteBackgroundJobStatusJob extends Job {
11 |
12 | @Override
13 | public void doJob() {
14 | DocumentJobStatus.delete("created < ?", new Date(new Date().getTime() - (60 * 60 * 1000)));
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/app/views/admin/Discussions/blank.html:
--------------------------------------------------------------------------------
1 | #{extends 'CRUD/layout.html' /}
2 | #{set title:messages.get('crud.blank.title', type.modelName) /}
3 |
4 | Please use the "Start a discussion" form on the frontend.
10 |15 | ${result.message} 16 |
17 | #{/else} 18 | 19 | 20 | -------------------------------------------------------------------------------- /public/javascripts/jquery.timeago.fr.js: -------------------------------------------------------------------------------- 1 | // French 2 | jQuery.timeago.settings.strings = { 3 | // environ ~= about, it's optional 4 | prefixAgo: "il y a", 5 | prefixFromNow: "d'ici", 6 | seconds: "moins d'une minute", 7 | minute: "environ une minute", 8 | minutes: "environ %d minutes", 9 | hour: "environ une heure", 10 | hours: "environ %d heures", 11 | day: "environ un jour", 12 | days: "environ %d jours", 13 | month: "environ un mois", 14 | months: "environ %d mois", 15 | year: "un an", 16 | years: "%d ans" 17 | }; -------------------------------------------------------------------------------- /app/models/UserRole.java: -------------------------------------------------------------------------------- 1 | package models; 2 | 3 | import models.deadbolt.Role; 4 | 5 | public class UserRole implements Role { 6 | 7 | public String name; 8 | 9 | public UserRole(String name) { 10 | this.name = name; 11 | } 12 | 13 | @Override 14 | public String getRoleName() { 15 | return this.name; 16 | } 17 | 18 | public final static String ADMIN = "admin"; 19 | public final static String MODERATOR = "moderator"; 20 | public final static String [] ROLES = {ADMIN, MODERATOR}; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /public/javascripts/jquery.timeago.en.js: -------------------------------------------------------------------------------- 1 | // English (Template) 2 | jQuery.timeago.settings.strings = { 3 | prefixAgo: null, 4 | prefixFromNow: null, 5 | suffixAgo: "ago", 6 | suffixFromNow: "from now", 7 | seconds: "less than a minute", 8 | minute: "about a minute", 9 | minutes: "%d minutes", 10 | hour: "about an hour", 11 | hours: "about %d hours", 12 | day: "a day", 13 | days: "%d days", 14 | month: "about a month", 15 | months: "%d months", 16 | year: "about a year", 17 | years: "%d years", 18 | wordSeparator: " ", 19 | numbers: [] 20 | }; 21 | -------------------------------------------------------------------------------- /app/jobs/IncrementDocumentCopyCountJob.java: -------------------------------------------------------------------------------- 1 | package jobs; 2 | 3 | import models.Document; 4 | import play.jobs.Job; 5 | 6 | public class IncrementDocumentCopyCountJob extends Job { 7 | 8 | private long documentId; 9 | 10 | public IncrementDocumentCopyCountJob(long documentId) { 11 | this.documentId = documentId; 12 | } 13 | 14 | @Override 15 | public void doJob() { 16 | Document document = Document.findById(this.documentId); 17 | if (document != null) { 18 | document.incrementCopyCountAndSave(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/jobs/IncrementDocumentReadCountJob.java: -------------------------------------------------------------------------------- 1 | package jobs; 2 | 3 | import models.Document; 4 | import play.jobs.Job; 5 | 6 | public class IncrementDocumentReadCountJob extends Job { 7 | 8 | private long documentId; 9 | 10 | public IncrementDocumentReadCountJob(long documentId) { 11 | this.documentId = documentId; 12 | } 13 | 14 | @Override 15 | public void doJob() { 16 | Document document = Document.findById(this.documentId); 17 | if (document != null) { 18 | document.incrementViewCountAndSave(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/jobs/IncrementDocumentDownloadCountJob.java: -------------------------------------------------------------------------------- 1 | package jobs; 2 | 3 | import models.Document; 4 | import play.jobs.Job; 5 | 6 | public class IncrementDocumentDownloadCountJob extends Job { 7 | 8 | private long documentId; 9 | 10 | public IncrementDocumentDownloadCountJob(long documentId) { 11 | this.documentId = documentId; 12 | } 13 | 14 | @Override 15 | public void doJob() { 16 | Document document = Document.findById(this.documentId); 17 | if (document != null) { 18 | document.incrementDownloadCountAndSave(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/controllers/web/Users.java: -------------------------------------------------------------------------------- 1 | package controllers.web; 2 | 3 | import java.util.List; 4 | 5 | import models.Discussion; 6 | import models.Document; 7 | import models.User; 8 | import play.mvc.With; 9 | import controllers.AppController; 10 | 11 | @With(WebController.class) 12 | public class Users extends AppController { 13 | 14 | public static void read(long id) { 15 | User user = User.findById(id); 16 | notFoundIfNull(user); 17 | List21 | &{'crud.add', type.modelName} 22 |
23 | 24 |21 | &{'crud.add', type.modelName} 22 |
23 | 24 |16 | This exception has been logged with id ${exception.id}. 17 |
18 | #{/if} 19 | #{/else} 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/views/admin/Discussions/list.html: -------------------------------------------------------------------------------- 1 | #{extends 'CRUD/layout.html' /} 2 | #{set title:messages.get('crud.list.title', type.name) /} 3 | 4 |21 | &{'crud.add', type.modelName} 22 |
23 | 24 |21 | &{'crud.add', type.modelName} 22 |
23 | 24 |21 | &{'crud.add', type.modelName} 22 |
23 | 24 |8 | 9 | &{'_.showMore'} 10 | 11 |
12 |18 | &{'document.list.end'} 19 |
20 |8 | 9 | &{'_.showMore'} 10 | 11 |
12 |18 | &{'document.list.end'} 19 |
20 ||
4 |
5 |
6 |
8 | ${_discussion.voteCount}
7 | |
9 |
10 |
11 |
12 |
14 | ${_discussion.viewCount}
13 | |
15 |
16 |
17 |
18 |
20 | ${_discussion.commentCount}
19 | |
21 |
22 |
23 |
24 |
26 | ${_discussion.documentCount}
25 | |
27 |
25 | 26 | 27 |
28 | #{/form} 29 |33 | 34 |
35 | #{/form} 36 | 37 |Automatically set
22 | #{/crud.custom} 23 | #{crud.custom 'updated' } 24 | 25 |Automatically set
26 | #{/crud.custom} 27 | #{/crud.form} 28 |29 | 30 | 31 | 32 |
33 | #{/form} 34 |29 | 30 | 31 |
32 | #{/form} 33 |37 | 38 |
39 | #{/form} 40 | 41 |29 | 30 | 31 |
32 | #{/form} 33 |37 | 38 |
39 | #{/form} 40 | 41 |29 | 30 | 31 |
32 | #{/form} 33 |37 | 38 |
39 | #{/form} 40 | 41 |9 | &{'comment.list.empty'} 10 |
11 | #{/else} 12 |36 | #{if objectType == 'document'} 37 | &{'comment.auth.login.needed'} 38 | #{/if} 39 | #{elseif objectType == 'discussion'} 40 | &{'comment.auth.login.needed'} 41 | #{/elseif} 42 |
43 | #{/else} 44 | -------------------------------------------------------------------------------- /app/controllers/api/Votes.java: -------------------------------------------------------------------------------- 1 | package controllers.api; 2 | 3 | import controllers.web.Auth; 4 | import models.Comment; 5 | import models.Document; 6 | import models.Vote; 7 | import models.User; 8 | import play.data.validation.Required; 9 | 10 | public class Votes extends ApiController { 11 | 12 | public static void create(@Required Vote vote) { 13 | checkAuthenticity(); 14 | if (!validation.hasErrors()) { 15 | User me = Auth.getMe(); 16 | Vote check = me.getVoteForObject(vote.objectType, vote.objectId); 17 | if (check == null) { 18 | vote.user = me; 19 | if (vote.validateAndSave()) { 20 | vote.updateCountForObject(true); 21 | renderJSON(vote); 22 | } 23 | } else { 24 | renderJSON(check); 25 | } 26 | } 27 | } 28 | 29 | public static void delete(long id) { 30 | checkAuthenticity(); 31 | User me = Auth.getMe(); 32 | Vote vote = Vote.findById(id); 33 | notFoundIfNull(vote); 34 | if (vote.user.id == me.id) { 35 | vote.updateCountForObject(false); 36 | Vote _vote = vote; 37 | vote.delete(); 38 | renderJSON(_vote); 39 | } else { 40 | unauthorized(); 41 | } 42 | } 43 | 44 | public static void read(@Required String objectType, @Required long objectId) { 45 | if (!validation.hasErrors()) { 46 | User me = Auth.getMe(); 47 | Vote vote = me.getVoteForObject(objectType, objectId); 48 | if (vote != null) { 49 | renderJSON(vote); 50 | } else { 51 | notFound(); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/controllers/api/ApiController.java: -------------------------------------------------------------------------------- 1 | package controllers.api; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import play.data.validation.Error; 7 | import play.i18n.Messages; 8 | import play.mvc.After; 9 | import play.mvc.Before; 10 | import controllers.AppController; 11 | import controllers.web.Auth; 12 | 13 | public class ApiController extends AppController { 14 | 15 | @Before(unless = { 16 | "api.Categories.list", 17 | "api.Categories.listDocuments", 18 | "api.Discussions.list", 19 | "api.Discussions.markAsViewed", 20 | "api.Documents.read", 21 | "api.Documents.readThumbnail", 22 | "api.Documents.markAsViewed", 23 | "api.Documents.download", 24 | "api.Documents.list" 25 | }) 26 | public static void checkAccess() { 27 | if (getMe() == null) { 28 | unauthorized(); 29 | } 30 | } 31 | 32 | @Before 33 | public static void setDefaultRequestParameters() { 34 | String pageParam = request.params.get("page"); 35 | if (pageParam != null) { 36 | int page = Integer.parseInt(pageParam); 37 | if (page < 1) { 38 | page = 1; 39 | } 40 | } 41 | } 42 | 43 | /** 44 | * Translates and sends error validation messages as a JSON array if any. 45 | */ 46 | @After 47 | public static void renderValidationErrors() { 48 | if (validation.hasErrors()) { 49 | response.status = 400; 50 | Map|
4 |
5 |
6 |
8 | ${_document.voteCount}
7 | |
9 |
10 |
11 |
12 |
14 | ${_document.copyCount}
13 | |
15 |
16 |
17 |
18 |
20 | ${_document.downloadCount}
19 | |
21 |
22 |
23 |
24 |
26 | ${_document.viewCount}
25 | |
27 |
28 |
29 |
30 |
32 | ${_document.commentCount}
31 | |
33 |
34 |
35 |
36 |
38 | ${_document.discussionCount}
37 | |
39 |
| Joined | 9 |${user.created} | 10 |
| Links | 13 |
14 |
|
19 |
| Karma | 22 |${user.karma} | 23 |
64 | 65 | 66 |
67 | #{/form} 68 |72 | 73 |
74 | #{/form} 75 | 76 |44 | Please note that you will be able to link additional documents to this discussion once you save it. 45 |
46 |52 | #{if keyword} 53 | &{'document.list.clearSearchOptions'} 54 | #{/if} 55 |
56 |7 | ${siteDescription} 8 |
9 |16 | &{'_.explore.expand'} 17 |
18 |23 | &{'_.discuss.expand'} 24 |
25 |30 | &{'_.share.expand'} 31 |
32 |54 | #{a @web.Documents.list()}All categories#{/a} 55 | #{list documentCategories} 56 | - #{a @web.Documents.list(null, _.id, null, null)}${_.name}#{/a} 57 | #{/list} 58 |
59 |74 | #{a @web.Discussions.list()}All categories#{/a} 75 | #{list discussionCategories} 76 | - #{a @web.Discussions.list(null, _.id, null, null)}${_.name}#{/a} 77 | #{/list} 78 |
79 |92 | Hello! This quick tour will guide through you the main features of this application. 93 |
94 |97 | Explore documents : read, comment and copy them directly to your Google Drive account. 98 |
99 |102 | Discussions are deeper conversations about documents. You can explore and read them here. You can also link additional documents to a discussion. 103 |
104 |107 | Upload a document to share it with others. A copy of that document will also be uploaded to your Google Drive. 108 |
109 |112 | Start a discussion : ask a question, post an idea or debate. Link documents to these discussions. 113 |
114 |117 | Quick search : access documents and discussions directly from here. 118 |
119 |122 | You can use this application without signing in. However for community features, you will need to sign in. 123 |
124 |52 | #{if keyword} 53 | &{'document.list.clearSearchOptions'} 54 | #{/if} 55 |
56 |Join our community!
99 |100 | #{a @web.Auth.googleCode(request.url), class : 'button large success'} 101 | 102 | &{'auth.login'} 103 | #{/a} 104 |
105 | × 106 |
12 | ${_comment.content} 13 |
14 |