From 2ae5d388076fac5aa6fa0cfe0bc5f97d2c97d223 Mon Sep 17 00:00:00 2001 From: Massimiliano Assante Date: Mon, 27 Nov 2023 16:42:53 +0100 Subject: [PATCH] first commit --- CHANGELOG.md | 84 ++ FUNDING.md | 26 + LICENSE.md | 311 ++++++ META-INF/KeySpace Structure.xlsx | Bin 0 -> 10851 bytes META-INF/MANIFEST.MF | 3 + META-INF/clientlog4j.properties | 13 + README.md | 42 + pom.xml | 151 +++ src/.DS_Store | Bin 0 -> 6148 bytes src/main/.DS_Store | Bin 0 -> 6148 bytes src/main/java/.DS_Store | Bin 0 -> 6148 bytes src/main/java/org/.DS_Store | Bin 0 -> 6148 bytes src/main/java/org/gcube/.DS_Store | Bin 0 -> 6148 bytes src/main/java/org/gcube/portal/.DS_Store | Bin 0 -> 6148 bytes .../java/org/gcube/portal/databook/.DS_Store | Bin 0 -> 6148 bytes .../databook/GCubeSocialNetworking.gwt.xml | 22 + .../client/GCubeSocialNetworking.java | 17 + .../portal/databook/client/util/Encoder.java | 15 + .../server/DBCassandraAstyanaxImpl.java | 945 ++++++++++++++++++ .../server/DatabookCassandraTest.java | 690 +++++++++++++ .../portal/databook/server/DatabookStore.java | 667 ++++++++++++ .../databook/server/RunningCluster.java | 220 ++++ .../gcube/portal/databook/server/Schema.java | 68 ++ .../gcube/portal/databook/server/Tester.java | 45 + .../server/resources/databook.properties | 4 + .../databook/shared/ApplicationProfile.java | 77 ++ .../portal/databook/shared/Attachment.java | 104 ++ .../databook/shared/ClientAttachment.java | 34 + .../portal/databook/shared/ClientFeed.java | 183 ++++ .../portal/databook/shared/ClientPost.java | 51 + .../gcube/portal/databook/shared/Comment.java | 175 ++++ .../portal/databook/shared/EnhancedFeed.java | 85 ++ .../gcube/portal/databook/shared/Feed.java | 322 ++++++ .../portal/databook/shared/FeedType.java | 19 + .../portal/databook/shared/ImageType.java | 5 + .../gcube/portal/databook/shared/Invite.java | 144 +++ .../shared/InviteOperationResult.java | 8 + .../portal/databook/shared/InviteStatus.java | 20 + .../gcube/portal/databook/shared/JSON.java | 10 + .../portal/databook/shared/JobStatusType.java | 53 + .../gcube/portal/databook/shared/Like.java | 88 ++ .../portal/databook/shared/Notification.java | 193 ++++ .../shared/NotificationChannelType.java | 20 + .../databook/shared/NotificationType.java | 181 ++++ .../gcube/portal/databook/shared/Post.java | 322 ++++++ .../portal/databook/shared/PostType.java | 18 + .../portal/databook/shared/PrivacyLevel.java | 9 + .../portal/databook/shared/RangeFeeds.java | 40 + .../portal/databook/shared/RangePosts.java | 40 + .../portal/databook/shared/RunningJob.java | 83 ++ .../shared/ShowUserStatisticAction.java | 25 + .../portal/databook/shared/UserInfo.java | 121 +++ .../ex/ColumnNameNotFoundException.java | 8 + .../shared/ex/CommentIDNotFoundException.java | 8 + .../shared/ex/FeedIDNotFoundException.java | 9 + .../shared/ex/FeedTypeNotFoundException.java | 8 + .../shared/ex/InviteIDNotFoundException.java | 8 + .../ex/InviteStatusNotFoundException.java | 8 + .../shared/ex/LikeIDNotFoundException.java | 8 + ...ificationChannelTypeNotFoundException.java | 8 + .../ex/NotificationIDNotFoundException.java | 8 + .../ex/NotificationTypeNotFoundException.java | 8 + .../ex/PrivacyLevelTypeNotFoundException.java | 8 + .../ex/TooManyRunningClustersException.java | 8 + .../antrun/build-printOutputDirectories.xml | 8 + target/antrun/build-seOuttputDirectories.xml | 16 + target/classes/META-INF/LICENSE.md | 311 ++++++ target/classes/META-INF/MANIFEST.MF | 13 + .../social-networking-library/pom.properties | 7 + .../social-networking-library/pom.xml | 152 +++ .../databook/GCubeSocialNetworking.gwt.xml | 22 + .../client/GCubeSocialNetworking.class | Bin 0 -> 866 bytes .../client/GCubeSocialNetworking.java | 17 + .../portal/databook/client/util/Encoder.class | Bin 0 -> 397 bytes .../portal/databook/client/util/Encoder.java | 15 + .../server/DBCassandraAstyanaxImpl.class | Bin 0 -> 29549 bytes .../server/DBCassandraAstyanaxImpl.java | 945 ++++++++++++++++++ .../server/DatabookCassandraTest.class | Bin 0 -> 973 bytes .../server/DatabookCassandraTest.java | 690 +++++++++++++ .../databook/server/DatabookStore.class | Bin 0 -> 9103 bytes .../portal/databook/server/DatabookStore.java | 667 ++++++++++++ .../databook/server/RunningCluster.class | Bin 0 -> 6971 bytes .../databook/server/RunningCluster.java | 220 ++++ .../gcube/portal/databook/server/Schema.class | Bin 0 -> 3102 bytes .../gcube/portal/databook/server/Schema.java | 68 ++ .../gcube/portal/databook/server/Tester.class | Bin 0 -> 3348 bytes .../gcube/portal/databook/server/Tester.java | 45 + .../server/resources/databook.properties | 4 + .../databook/shared/ApplicationProfile.class | Bin 0 -> 2256 bytes .../databook/shared/ApplicationProfile.java | 77 ++ .../Attachment$AttachmentJsonizer.class | Bin 0 -> 295 bytes .../portal/databook/shared/Attachment.class | Bin 0 -> 2345 bytes .../portal/databook/shared/Attachment.java | 104 ++ .../databook/shared/ClientAttachment.class | Bin 0 -> 1086 bytes .../databook/shared/ClientAttachment.java | 34 + .../ClientFeed$ClientFeedJsonizer.class | Bin 0 -> 295 bytes .../portal/databook/shared/ClientFeed.class | Bin 0 -> 5303 bytes .../portal/databook/shared/ClientFeed.java | 183 ++++ .../portal/databook/shared/ClientPost.class | Bin 0 -> 1730 bytes .../portal/databook/shared/ClientPost.java | 51 + .../portal/databook/shared/Comment.class | Bin 0 -> 4064 bytes .../gcube/portal/databook/shared/Comment.java | 175 ++++ .../portal/databook/shared/EnhancedFeed.class | Bin 0 -> 3568 bytes .../portal/databook/shared/EnhancedFeed.java | 85 ++ .../gcube/portal/databook/shared/Feed.class | Bin 0 -> 8094 bytes .../gcube/portal/databook/shared/Feed.java | 322 ++++++ .../portal/databook/shared/FeedType.class | Bin 0 -> 1377 bytes .../portal/databook/shared/FeedType.java | 19 + .../portal/databook/shared/ImageType.class | Bin 0 -> 1275 bytes .../portal/databook/shared/ImageType.java | 5 + .../gcube/portal/databook/shared/Invite.class | Bin 0 -> 3104 bytes .../gcube/portal/databook/shared/Invite.java | 144 +++ .../shared/InviteOperationResult.class | Bin 0 -> 1250 bytes .../shared/InviteOperationResult.java | 8 + .../portal/databook/shared/InviteStatus.class | Bin 0 -> 1250 bytes .../portal/databook/shared/InviteStatus.java | 20 + .../gcube/portal/databook/shared/JSON.class | Bin 0 -> 611 bytes .../gcube/portal/databook/shared/JSON.java | 10 + .../databook/shared/JobStatusType.class | Bin 0 -> 1667 bytes .../portal/databook/shared/JobStatusType.java | 53 + .../gcube/portal/databook/shared/Like.class | Bin 0 -> 2250 bytes .../gcube/portal/databook/shared/Like.java | 88 ++ .../portal/databook/shared/Notification.class | Bin 0 -> 4704 bytes .../portal/databook/shared/Notification.java | 193 ++++ .../shared/NotificationChannelType.class | Bin 0 -> 1262 bytes .../shared/NotificationChannelType.java | 20 + .../databook/shared/NotificationType.class | Bin 0 -> 4020 bytes .../databook/shared/NotificationType.java | 181 ++++ .../gcube/portal/databook/shared/Post.class | Bin 0 -> 8075 bytes .../gcube/portal/databook/shared/Post.java | 322 ++++++ .../portal/databook/shared/PostType.class | Bin 0 -> 1358 bytes .../portal/databook/shared/PostType.java | 18 + .../portal/databook/shared/PrivacyLevel.class | Bin 0 -> 1320 bytes .../portal/databook/shared/PrivacyLevel.java | 9 + .../portal/databook/shared/RangeFeeds.class | Bin 0 -> 1413 bytes .../portal/databook/shared/RangeFeeds.java | 40 + .../portal/databook/shared/RangePosts.class | Bin 0 -> 1402 bytes .../portal/databook/shared/RangePosts.java | 40 + .../portal/databook/shared/RunningJob.class | Bin 0 -> 2554 bytes .../portal/databook/shared/RunningJob.java | 83 ++ .../shared/ShowUserStatisticAction.class | Bin 0 -> 1796 bytes .../shared/ShowUserStatisticAction.java | 25 + .../portal/databook/shared/UserInfo.class | Bin 0 -> 3448 bytes .../portal/databook/shared/UserInfo.java | 121 +++ .../ex/ColumnNameNotFoundException.class | Bin 0 -> 445 bytes .../ex/ColumnNameNotFoundException.java | 8 + .../ex/CommentIDNotFoundException.class | Bin 0 -> 442 bytes .../shared/ex/CommentIDNotFoundException.java | 8 + .../shared/ex/FeedIDNotFoundException.class | Bin 0 -> 728 bytes .../shared/ex/FeedIDNotFoundException.java | 9 + .../shared/ex/FeedTypeNotFoundException.class | Bin 0 -> 439 bytes .../shared/ex/FeedTypeNotFoundException.java | 8 + .../shared/ex/InviteIDNotFoundException.class | Bin 0 -> 439 bytes .../shared/ex/InviteIDNotFoundException.java | 8 + .../ex/InviteStatusNotFoundException.class | Bin 0 -> 451 bytes .../ex/InviteStatusNotFoundException.java | 8 + .../shared/ex/LikeIDNotFoundException.class | Bin 0 -> 433 bytes .../shared/ex/LikeIDNotFoundException.java | 8 + ...ficationChannelTypeNotFoundException.class | Bin 0 -> 484 bytes ...ificationChannelTypeNotFoundException.java | 8 + .../ex/NotificationIDNotFoundException.class | Bin 0 -> 457 bytes .../ex/NotificationIDNotFoundException.java | 8 + .../NotificationTypeNotFoundException.class | Bin 0 -> 463 bytes .../ex/NotificationTypeNotFoundException.java | 8 + .../PrivacyLevelTypeNotFoundException.class | Bin 0 -> 463 bytes .../ex/PrivacyLevelTypeNotFoundException.java | 8 + .../ex/TooManyRunningClustersException.class | Bin 0 -> 457 bytes .../ex/TooManyRunningClustersException.java | 8 + target/maven-archiver/pom.properties | 3 + .../compile/default-compile/createdFiles.lst | 0 .../compile/default-compile/inputFiles.lst | 47 + ...tworking-library-1.18.0-SNAPSHOT-tests.jar | Bin 0 -> 2727 bytes ...ial-networking-library-1.18.0-SNAPSHOT.jar | Bin 0 -> 114987 bytes 173 files changed, 11627 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 FUNDING.md create mode 100644 LICENSE.md create mode 100644 META-INF/KeySpace Structure.xlsx create mode 100644 META-INF/MANIFEST.MF create mode 100644 META-INF/clientlog4j.properties create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/.DS_Store create mode 100644 src/main/.DS_Store create mode 100644 src/main/java/.DS_Store create mode 100644 src/main/java/org/.DS_Store create mode 100644 src/main/java/org/gcube/.DS_Store create mode 100644 src/main/java/org/gcube/portal/.DS_Store create mode 100644 src/main/java/org/gcube/portal/databook/.DS_Store create mode 100644 src/main/java/org/gcube/portal/databook/GCubeSocialNetworking.gwt.xml create mode 100644 src/main/java/org/gcube/portal/databook/client/GCubeSocialNetworking.java create mode 100644 src/main/java/org/gcube/portal/databook/client/util/Encoder.java create mode 100644 src/main/java/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java create mode 100644 src/main/java/org/gcube/portal/databook/server/DatabookCassandraTest.java create mode 100644 src/main/java/org/gcube/portal/databook/server/DatabookStore.java create mode 100644 src/main/java/org/gcube/portal/databook/server/RunningCluster.java create mode 100644 src/main/java/org/gcube/portal/databook/server/Schema.java create mode 100644 src/main/java/org/gcube/portal/databook/server/Tester.java create mode 100644 src/main/java/org/gcube/portal/databook/server/resources/databook.properties create mode 100644 src/main/java/org/gcube/portal/databook/shared/ApplicationProfile.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/Attachment.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ClientAttachment.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ClientFeed.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ClientPost.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/Comment.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/EnhancedFeed.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/Feed.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/FeedType.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ImageType.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/Invite.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/InviteOperationResult.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/InviteStatus.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/JSON.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/JobStatusType.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/Like.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/Notification.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/NotificationChannelType.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/NotificationType.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/Post.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/PostType.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/PrivacyLevel.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/RangeFeeds.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/RangePosts.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/RunningJob.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ShowUserStatisticAction.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/UserInfo.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java create mode 100644 src/main/java/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java create mode 100644 target/antrun/build-printOutputDirectories.xml create mode 100644 target/antrun/build-seOuttputDirectories.xml create mode 100644 target/classes/META-INF/LICENSE.md create mode 100644 target/classes/META-INF/MANIFEST.MF create mode 100644 target/classes/META-INF/maven/org.gcube.portal/social-networking-library/pom.properties create mode 100644 target/classes/META-INF/maven/org.gcube.portal/social-networking-library/pom.xml create mode 100644 target/classes/org/gcube/portal/databook/GCubeSocialNetworking.gwt.xml create mode 100644 target/classes/org/gcube/portal/databook/client/GCubeSocialNetworking.class create mode 100644 target/classes/org/gcube/portal/databook/client/GCubeSocialNetworking.java create mode 100644 target/classes/org/gcube/portal/databook/client/util/Encoder.class create mode 100644 target/classes/org/gcube/portal/databook/client/util/Encoder.java create mode 100644 target/classes/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.class create mode 100644 target/classes/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java create mode 100644 target/classes/org/gcube/portal/databook/server/DatabookCassandraTest.class create mode 100644 target/classes/org/gcube/portal/databook/server/DatabookCassandraTest.java create mode 100644 target/classes/org/gcube/portal/databook/server/DatabookStore.class create mode 100644 target/classes/org/gcube/portal/databook/server/DatabookStore.java create mode 100644 target/classes/org/gcube/portal/databook/server/RunningCluster.class create mode 100644 target/classes/org/gcube/portal/databook/server/RunningCluster.java create mode 100644 target/classes/org/gcube/portal/databook/server/Schema.class create mode 100644 target/classes/org/gcube/portal/databook/server/Schema.java create mode 100644 target/classes/org/gcube/portal/databook/server/Tester.class create mode 100644 target/classes/org/gcube/portal/databook/server/Tester.java create mode 100644 target/classes/org/gcube/portal/databook/server/resources/databook.properties create mode 100644 target/classes/org/gcube/portal/databook/shared/ApplicationProfile.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ApplicationProfile.java create mode 100644 target/classes/org/gcube/portal/databook/shared/Attachment$AttachmentJsonizer.class create mode 100644 target/classes/org/gcube/portal/databook/shared/Attachment.class create mode 100644 target/classes/org/gcube/portal/databook/shared/Attachment.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ClientAttachment.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ClientAttachment.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ClientFeed$ClientFeedJsonizer.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ClientFeed.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ClientFeed.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ClientPost.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ClientPost.java create mode 100644 target/classes/org/gcube/portal/databook/shared/Comment.class create mode 100644 target/classes/org/gcube/portal/databook/shared/Comment.java create mode 100644 target/classes/org/gcube/portal/databook/shared/EnhancedFeed.class create mode 100644 target/classes/org/gcube/portal/databook/shared/EnhancedFeed.java create mode 100644 target/classes/org/gcube/portal/databook/shared/Feed.class create mode 100644 target/classes/org/gcube/portal/databook/shared/Feed.java create mode 100644 target/classes/org/gcube/portal/databook/shared/FeedType.class create mode 100644 target/classes/org/gcube/portal/databook/shared/FeedType.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ImageType.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ImageType.java create mode 100644 target/classes/org/gcube/portal/databook/shared/Invite.class create mode 100644 target/classes/org/gcube/portal/databook/shared/Invite.java create mode 100644 target/classes/org/gcube/portal/databook/shared/InviteOperationResult.class create mode 100644 target/classes/org/gcube/portal/databook/shared/InviteOperationResult.java create mode 100644 target/classes/org/gcube/portal/databook/shared/InviteStatus.class create mode 100644 target/classes/org/gcube/portal/databook/shared/InviteStatus.java create mode 100644 target/classes/org/gcube/portal/databook/shared/JSON.class create mode 100644 target/classes/org/gcube/portal/databook/shared/JSON.java create mode 100644 target/classes/org/gcube/portal/databook/shared/JobStatusType.class create mode 100644 target/classes/org/gcube/portal/databook/shared/JobStatusType.java create mode 100644 target/classes/org/gcube/portal/databook/shared/Like.class create mode 100644 target/classes/org/gcube/portal/databook/shared/Like.java create mode 100644 target/classes/org/gcube/portal/databook/shared/Notification.class create mode 100644 target/classes/org/gcube/portal/databook/shared/Notification.java create mode 100644 target/classes/org/gcube/portal/databook/shared/NotificationChannelType.class create mode 100644 target/classes/org/gcube/portal/databook/shared/NotificationChannelType.java create mode 100644 target/classes/org/gcube/portal/databook/shared/NotificationType.class create mode 100644 target/classes/org/gcube/portal/databook/shared/NotificationType.java create mode 100644 target/classes/org/gcube/portal/databook/shared/Post.class create mode 100644 target/classes/org/gcube/portal/databook/shared/Post.java create mode 100644 target/classes/org/gcube/portal/databook/shared/PostType.class create mode 100644 target/classes/org/gcube/portal/databook/shared/PostType.java create mode 100644 target/classes/org/gcube/portal/databook/shared/PrivacyLevel.class create mode 100644 target/classes/org/gcube/portal/databook/shared/PrivacyLevel.java create mode 100644 target/classes/org/gcube/portal/databook/shared/RangeFeeds.class create mode 100644 target/classes/org/gcube/portal/databook/shared/RangeFeeds.java create mode 100644 target/classes/org/gcube/portal/databook/shared/RangePosts.class create mode 100644 target/classes/org/gcube/portal/databook/shared/RangePosts.java create mode 100644 target/classes/org/gcube/portal/databook/shared/RunningJob.class create mode 100644 target/classes/org/gcube/portal/databook/shared/RunningJob.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ShowUserStatisticAction.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ShowUserStatisticAction.java create mode 100644 target/classes/org/gcube/portal/databook/shared/UserInfo.class create mode 100644 target/classes/org/gcube/portal/databook/shared/UserInfo.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.class create mode 100644 target/classes/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java create mode 100644 target/maven-archiver/pom.properties create mode 100644 target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 target/social-networking-library-1.18.0-SNAPSHOT-tests.jar create mode 100644 target/social-networking-library-1.18.0-SNAPSHOT.jar diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..eb3b518 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,84 @@ + +# Changelog for Social Networking Library + +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [v2.0.0] - 2023-11-15 + + - Feature #25901-fix, same as feature 25901 but with minor fixes related to deprecated methods and classes + +## [v1.18.0-SNAPSHOT] - 2023-10-30 + +- Implementation of databookstore using rest api of social service client + +## [v1.17.0] - 2022-05-13 + + - Added support for Catalogue notifications + - Ported to git + +## [v1.16.1] - 2018-03-07 + + - Added JsInterop DTOs (ClientPost, ClientAttachment and JSON) for supporting new IPC Client side in NewsFeed + +## [v1.16.0] - 2017-05-25 + + - Added feature for hashtags in comments + +## [v1.15.0] - 2017-01-25 + + - Added support for job completion notifications + - Improved exceptions handling + +## [v1.14.0] - 2016-09-29 + + - Upgraded astyanax dependency to 2.0.2 + - Removed support for Document Workflow notification + +## [v1.13.0] - 2016-09-05 + + - Method to close connections pool to Apache Cassandra added + - Added methods to retrieve recent user's commented and liked posts + - Added enum class ShowUserStatisticAction + +## [v1.10.0] - 2016-01-22 + + - Feature #1982, multi attachments to posts + +## [v1.9.0] - 2016-01-15 + + - Feature #1663, for user statistics fast retrieval + - Feature #1493, updated the way we instanciate keyspace, now it is more efficient + - Fix Bug #246, updated methods for editing comments + +## [v1.8.0] - 2015-07-03 + + - Added feature for invites and hashtags + +## [v1.6.0] - 2014-04-08 + + - Added feature for post retrieval by range + - Added feature for notifications retrieval by range + - Added feature for unlike + +## [v1.5.0] - 2014-03-05 + + - Added feature for post alert notifications + +## [v1.3.0] - 2013-07-08 + + - Added feature for calendar notifications + - Added feature for URL encoding decoding js base 6 + +## [v1.2.0] - 2013-05-29 + + - Added feature for fine grained notifications + +## [v1.1.0] - 2013-04-19 + + - Added feature for people taggings (mentions) + - Fix for method getAllPortalPrivacyLevelFeeds() not recongnizing application posts + +## [v1.0.0] - 2013-01-11 + +- First release diff --git a/FUNDING.md b/FUNDING.md new file mode 100644 index 0000000..6fa9eac --- /dev/null +++ b/FUNDING.md @@ -0,0 +1,26 @@ +# Acknowledgments + +The projects leading to this software have received funding from a series of European Union programmes including: + +- the Sixth Framework Programme for Research and Technological Development + - [DILIGENT](https://cordis.europa.eu/project/id/004260) (grant no. 004260). +- the Seventh Framework Programme for research, technological development and demonstration + - [D4Science](https://cordis.europa.eu/project/id/212488) (grant no. 212488); + - [D4Science-II](https://cordis.europa.eu/project/id/239019) (grant no.239019); + - [ENVRI](https://cordis.europa.eu/project/id/283465) (grant no. 283465); + - [iMarine](https://cordis.europa.eu/project/id/283644) (grant no. 283644); + - [EUBrazilOpenBio](https://cordis.europa.eu/project/id/288754) (grant no. 288754). +- the H2020 research and innovation programme + - [SoBigData](https://cordis.europa.eu/project/id/654024) (grant no. 654024); + - [PARTHENOS](https://cordis.europa.eu/project/id/654119) (grant no. 654119); + - [EGI-Engage](https://cordis.europa.eu/project/id/654142) (grant no. 654142); + - [ENVRI PLUS](https://cordis.europa.eu/project/id/654182) (grant no. 654182); + - [BlueBRIDGE](https://cordis.europa.eu/project/id/675680) (grant no. 675680); + - [PerformFISH](https://cordis.europa.eu/project/id/727610) (grant no. 727610); + - [AGINFRA PLUS](https://cordis.europa.eu/project/id/731001) (grant no. 731001); + - [DESIRA](https://cordis.europa.eu/project/id/818194) (grant no. 818194); + - [ARIADNEplus](https://cordis.europa.eu/project/id/823914) (grant no. 823914); + - [RISIS 2](https://cordis.europa.eu/project/id/824091) (grant no. 824091); + - [EOSC-Pillar](https://cordis.europa.eu/project/id/857650) (grant no. 857650); + - [Blue Cloud](https://cordis.europa.eu/project/id/862409) (grant no. 862409); + - [SoBigData-PlusPlus](https://cordis.europa.eu/project/id/871042) (grant no. 871042); \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..c25566d --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,311 @@ +#European Union Public Licence V.1.1 + +##*EUPL © the European Community 2007* + + +This **European Union Public Licence** (the **“EUPL”**) applies to the Work or Software +(as defined below) which is provided under the terms of this Licence. Any use of +the Work, other than as authorised under this Licence is prohibited (to the +extent such use is covered by a right of the copyright holder of the Work). + +The Original Work is provided under the terms of this Licence when the Licensor +(as defined below) has placed the following notice immediately following the +copyright notice for the Original Work: + +**Licensed under the EUPL V.1.1** + +or has expressed by any other mean his willingness to license under the EUPL. + + + +##1. Definitions + +In this Licence, the following terms have the following meaning: + +- The Licence: this Licence. + +- The Original Work or the Software: the software distributed and/or + communicated by the Licensor under this Licence, available as Source Code and + also as Executable Code as the case may be. + +- Derivative Works: the works or software that could be created by the Licensee, + based upon the Original Work or modifications thereof. This Licence does not + define the extent of modification or dependence on the Original Work required + in order to classify a work as a Derivative Work; this extent is determined by + copyright law applicable in the country mentioned in Article 15. + +- The Work: the Original Work and/or its Derivative Works. + +- The Source Code: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- The Executable Code: any code which has generally been compiled and which is + meant to be interpreted by a computer as a program. + +- The Licensor: the natural or legal person that distributes and/or communicates + the Work under the Licence. + +- Contributor(s): any natural or legal person who modifies the Work under the + Licence, or otherwise contributes to the creation of a Derivative Work. + +- The Licensee or “You”: any natural or legal person who makes any usage of the + Software under the terms of the Licence. + +- Distribution and/or Communication: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, on-line or off-line, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + + + +##2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a world-wide, royalty-free, non-exclusive, +sub-licensable licence to do the following, for the duration of copyright vested +in the Original Work: + +- use the Work in any circumstance and for all usage, reproduce the Work, modify +- the Original Work, and make Derivative Works based upon the Work, communicate +- to the public, including the right to make available or display the Work or +- copies thereof to the public and perform publicly, as the case may be, the +- Work, distribute the Work or copies thereof, lend and rent the Work or copies +- thereof, sub-license rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make effective +the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non exclusive usage rights to +any patents held by the Licensor, to the extent necessary to make use of the +rights granted on the Work under this Licence. + + + +##3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, in +a notice following the copyright notice attached to the Work, a repository where +the Source Code is easily and freely accessible for as long as the Licensor +continues to distribute and/or communicate the Work. + + + +##4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits from +any exception or limitation to the exclusive rights of the rights owners in the +Original Work or Software, of the exhaustion of those rights or of other +applicable limitations thereto. + + + +##5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: the Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and a +copy of the Licence with every copy of the Work he/she distributes and/or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes and/or communicates copies of the +Original Works or Derivative Works based upon the Original Work, this +Distribution and/or Communication will be done under the terms of this Licence +or of a later version of this Licence unless the Original Work is expressly +distributed only under this version of the Licence. The Licensee (becoming +Licensor) cannot offer or impose any additional terms or conditions on the Work +or Derivative Work that alter or restrict the terms of the Licence. + +Compatibility clause: If the Licensee Distributes and/or Communicates Derivative +Works or copies thereof based upon both the Original Work and another work +licensed under a Compatible Licence, this Distribution and/or Communication can +be done under the terms of this Compatible Licence. For the sake of this clause, +“Compatible Licence” refers to the licences listed in the appendix attached to +this Licence. Should the Licensee’s obligations under the Compatible Licence +conflict with his/her obligations under this Licence, the obligations of the +Compatible Licence shall prevail. + +Provision of Source Code: When distributing and/or communicating copies of the +Work, the Licensee will provide a machine-readable copy of the Source Code or +indicate a repository where this Source will be easily and freely available for +as long as the Licensee continues to distribute and/or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade names, +trademarks, service marks, or names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the copyright notice. + + + +##6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she brings +to the Work are owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + + + +##7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +contributors. It is not a finished work and may therefore contain defects or +“bugs” inherent to this type of software development. + +For the above reason, the Work is provided under the Licence on an “as is” basis +and without warranties of any kind concerning the Work, including without +limitation merchantability, fitness for a particular purpose, absence of defects +or errors, accuracy, non-infringement of intellectual property rights other than +copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a condition +for the grant of any rights to the Work. + + + +##8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the use +of the Work, including without limitation, damages for loss of goodwill, work +stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such +damage. However, the Licensor will be liable under statutory product liability +laws as far such laws apply to the Work. + + + +##9. Additional agreements + +While distributing the Original Work or Derivative Works, You may choose to +conclude an additional agreement to offer, and charge a fee for, acceptance of +support, warranty, indemnity, or other liability obligations and/or services +consistent with this Licence. However, in accepting such obligations, You may +act only on your own behalf and on your sole responsibility, not on behalf of +the original Licensor or any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred +by, or claims asserted against such Contributor by the fact You have accepted +any such warranty or additional liability. + + + +##10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon “I agree” +placed under the bottom of a window displaying the text of this Licence or by +affirming consent in any other similar way, in accordance with the rules of +applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this Licence, +such as the use of the Work, the creation by You of a Derivative Work or the +Distribution and/or Communication by You of the Work or copies thereof. + + + +##11. Information to the public + +In case of any Distribution and/or Communication of the Work by means of +electronic communication by You (for example, by offering to download the Work +from a remote location) the distribution channel or media (for example, a +website) must at least provide to the public the information requested by the +applicable law regarding the Licensor, the Licence and the way it may be +accessible, concluded, stored and reproduced by the Licensee. + + + +##12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + + + +##13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work licensed hereunder. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed and/or reformed so as necessary to make +it valid and enforceable. + +The European Commission may publish other linguistic versions and/or new +versions of this Licence, so far this is required and reasonable, without +reducing the scope of the rights granted by the Licence. New versions of the +Licence will be published with a unique version number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + + + +##14. Jurisdiction + +Any litigation resulting from the interpretation of this License, arising +between the European Commission, as a Licensor, and any Licensee, will be +subject to the jurisdiction of the Court of Justice of the European Communities, +as laid down in article 238 of the Treaty establishing the European Community. + +Any litigation arising between Parties, other than the European Commission, and +resulting from the interpretation of this License, will be subject to the +exclusive jurisdiction of the competent court where the Licensor resides or +conducts its primary business. + + + +##15. Applicable Law + +This Licence shall be governed by the law of the European Union country where +the Licensor resides or has his registered office. + +This licence shall be governed by the Belgian law if: + +- a litigation arises between the European Commission, as a Licensor, and any +- Licensee; the Licensor, other than the European Commission, has no residence +- or registered office inside a European Union country. + + +--- + + +##Appendix + + +**“Compatible Licences”** according to article 5 EUPL are: + + +- GNU General Public License (GNU GPL) v. 2 + +- Open Software License (OSL) v. 2.1, v. 3.0 + +- Common Public License v. 1.0 + +- Eclipse Public License v. 1.0 + +- Cecill v. 2.0 \ No newline at end of file diff --git a/META-INF/KeySpace Structure.xlsx b/META-INF/KeySpace Structure.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6ee9994891dfcb02ad4cc028950a85022bdb7ad3 GIT binary patch literal 10851 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 literal 0 HcmV?d00001 diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000..ed49fc3 --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: org.gcube.portal.databook.server.Tester + diff --git a/META-INF/clientlog4j.properties b/META-INF/clientlog4j.properties new file mode 100644 index 0000000..574c7b1 --- /dev/null +++ b/META-INF/clientlog4j.properties @@ -0,0 +1,13 @@ +log4j.rootLogger=DEBUG, A1 +log4j.appender.A1=org.apache.log4j.ConsoleAppender +log4j.appender.A1.layout=org.apache.log4j.PatternLayout + +# Print the date in ISO 8601 format +log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n + +# Print only messages of level TRACE or above in the package org.gcube +log4j.logger.org.gcube=TRACE +log4j.logger.org.gcube.application.framework.core.session=INFO +log4j.logger.com.netflix.astyanax.connectionpool=ERROR +log4j.logger.org.gcube.portal.databook.server.DBCassandraAstyanaxImpl=TRACE +log4j.logger.org.gcube.common=ERROR \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5eeaa31 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# gCube System - Social Networking Library + +The gCube Social Networking Library is the 'bridge' between your gCube Applications and the social networking facilities. +The social networking facilities exploit a NoSQL data store for their storage. Specifically an Apache Cassandra data store. + +## Structure of the project + +* The source code is present in the src folder. + +## Built With + +* [OpenJDK](https://openjdk.java.net/) - The JDK used +* [Maven](https://maven.apache.org/) - Dependency Management + +## Documentation + +* Use of this service is described in the [Wiki](https://wiki.gcube-system.org/gcube/Social_Networking_Library). + +## Change log + +See [Releases](https://code-repo.d4science.org/gCubeSystem/social-util-library/releases). + +## Authors + +* **Massimiliano Assante** ([ORCID](https://orcid.org/0000-0002-3761-1492)) - [ISTI-CNR Infrascience Group](https://www.isti.cnr.it/People/M.Assante) + +## Maintainers + +* **Massimiliano Assante** ([ORCID](https://orcid.org/0000-0002-3761-1492)) - [ISTI-CNR Infrascience Group](https://www.isti.cnr.it/People/M.Assante) + +## License + +This project is licensed under the EUPL V.1.1 License - see the [LICENSE.md](LICENSE.md) file for details. + + +## About the gCube Framework +This software is part of the [gCubeFramework](https://www.gcube-system.org/ "gCubeFramework"): an +open-source software toolkit used for building and operating Hybrid Data +Infrastructures enabling the dynamic deployment of Virtual Research Environments +by favouring the realisation of reuse oriented policies. + +The projects leading to this software have received funding from a series of European Union programmes see [FUNDING.md](FUNDING.md) \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6e2b5fc --- /dev/null +++ b/pom.xml @@ -0,0 +1,151 @@ + + 4.0.0 + + maven-parent + org.gcube.tools + 1.1.0 + + + + org.gcube.portal + social-library-stubs + 1.0.0-SNAPSHOT + gCube Social Library stubs + + The gCube Social Networking Library stubs exploits the social networking facilities using the social-service-client to interface with the NoSQL data store for their storage. Specifically an Apache Cassandra data store. + + + scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId} + scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId} + https://code-repo.d4science.org/gCubeSystem/${project.artifactId} + + + 1.8 + 1.8 + 2.8.1 + UTF-8 + UTF-8 + 4.13.0 + 1.2.3 + + + + + org.gcube.distribution + maven-portal-bom + 3.6.4 + pom + import + + + + + + org.gcube.social-networking + social-service-client + [1.3.0-SNAPSHOT, 2.0.0) + + + com.google + gwt-jsonmaker + 1.2.1 + + + org.gcube.resources.discovery + ic-client + provided + + + org.gcube.common.portal + portal-manager + provided + + + com.sun.mail + javax.mail + provided + + + junit + junit + 4.8 + + + com.google.gwt + gwt-user + ${gwtVersion} + provided + + + org.slf4j + slf4j-log4j12 + + + org.slf4j + slf4j-api + + + commons-lang + commons-lang + 2.6 + + + + + + src/main/java + + **/*.* + + + + + + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + org.apache.maven.plugins + maven-javadoc-plugin + + -Xdoclint:none + -Xdoclint:none + + 3.1.0 + + + generate-doc + install + + jar + + + + + + + + \ No newline at end of file diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d823f8831a6191d8c247d25888ab1252dfaadf6a GIT binary patch literal 6148 zcmeHK%}T>S5Z-O0Nhm@N3VI88Etq192QMMk7cim+m70*E!8BW%)Er77cYPsW#OHBl zcOw?-Rm9G~?l-@?*$=Wmj4>X}lOAIZW6Xkv$Wd7%=w2IY>10HXW5iW4jWZF0{ib7o z9q`)?HenGOxHci{?n0Mi$sKPQT=S2|BZqT|EB8wY6im%df zHF9>(L|#T|KAy>fG#Nw6?RAPA^7J*(4V)ict=POWD!bz$+-93wjP`c_#7)@HP2O9w9M63=jjvz{WD5 zj|8i;u?*0{i2-8ZCkAkTaG@dk8f%4e>wpfg&loolQ9#GH1fr|a*H|lr2nbiDfU1=1 zCk9vL;CFSNud!CB${Ck4!#H~8=JCSi?BI80I^(`V>WKkjV3mQkG95hs&*7I@`^aA{ zA&VFw2L2fX+!%(#02Zas)^E$hv(|-n4-EzLYE(c#U%3Q;f&0k5463+`I^_8pYlS!p S`eivFT?8Z{)DZ)}z`zG07fN{m literal 0 HcmV?d00001 diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cc50cedf75ef88583a10bba8c75e7ab2d09ee58b GIT binary patch literal 6148 zcmeHK%}T>S5Z<-XBorYB1-%8l7EH0lgO?EN3mDOZN=-=7Xv~%-Z4RZ7yS|Vw;`2DO zyAg}^Dq?3~_nY6{><8H&#uyK#NtZE)F=jzS zs-d%UD)KT)^U*{Wq{#?UZm!Zi5mg|jc~Z#QPz7w;vWL$8eBSHzJ8rkm7s9 zKk6?QwzYe3cyc~`%ARxaq8Q~sxRh;;4ZMQ#xu97%$up7PgRjYN@(76mVt^PR2G*7V zeI!`zwPk=7P7DwOKQVy&g9{DO*H|l*TL*M_ea5(fhypskB@kVWzQ$T1L_oMI1yrS6 zKQXu}2fwTHe2uk2RnEAa8OG5wH;)%CX9vG4(;4>_QcnyJ1IrAwlv1h6Q5wtib4p0zHtJ7_4FSEB*~`qCu;4BSWdWKhLj)FIE;SS!R) T&@amY=^`Krp^g~%1qMCS5Z-O8Nhm@N3VI88Etq192QMMk7cim+m70)JgE3o@)Er77cYPsW#OHBl zcLNr47O^w1`_1oe_JiyXV~qRDc*vN|7&DS zfEf5^4DjA0nE0?LeYXBs9-g%hv`1(tm{+3$0{X@!01Vtm4rNfq9n>Mu(^xCSQP3~T Q0qG(j389V{_yq>O0Bf&Fwg3PC literal 0 HcmV?d00001 diff --git a/src/main/java/org/.DS_Store b/src/main/java/org/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b8cef80f5a6066a6b0cd19b8d913e7ef7538db32 GIT binary patch literal 6148 zcmeHK%SyvQ6rJhACKMqH1>FVQ7EH0lg_{uT4;ayfN=;0t!I&vcY8R!Dz5b9t;`ey( z%mi8tE=BCUFmvv6CUYS3V2p8Z9`zZs7-I%BM2W=AtQqES zy71fEY{DMdoP})t`#-{In&gG!eDX%K)!ylJ%ucs+?>~u!Uj)TG_k!6iT314(VWkJ* zbrLVe*50|uiXh42nJh@67*g(Tk}MJnPt3C@m$kkMn5JQlt;6MVFc|ji{=ixF>}B6M z1!H(JT&+xF|LFMaa{QdWWa3RR$$@eyyBaHa2W4$Zul_7cMK%F%RZ(RU5(C5lF+dD# zB?J06FuGg0dRjCwKn(oE0PYVqG(=ZpsZeem(BbtN<1IuK(D5ySXlryemI@&P!c{4t zD&_i#!BsiEO6dRq literal 0 HcmV?d00001 diff --git a/src/main/java/org/gcube/.DS_Store b/src/main/java/org/gcube/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b2697e4f7abe8fe22ac931cf1d5af7041f5f0884 GIT binary patch literal 6148 zcmeHK%}T>S5Z-NTlTd^l6!aGGS}?^H4_-p7FJMFuDm5WRgE3o@)E-J9cYPsW#OHBl zcXJ2^youNu*!|{rH~T^MhcU+eWjtccW{jE85IHI>g6`H(M<*k4IY!9RXjLqtR75QU z{Y4jkd!H?sU^y#U^ZP%dMVb_)>wfZ1x3|+b49gf8_ra4`1!Y(+3qQ_p|c*j zr(jG@CYz0A?jIeWUCy4k{2W2F!xAY7FK zs#30>7+jTu-_d!V#!8_oXI#z<S5Z-O8Nhm@N3VI88Etq192QMMk7cim+m70*Ep)o5>Y7V84yS|Vw;`2DO zyAewiJc-zuGW*TWPnP{scCw5y?$6^sV>V;V1VwCFFnl2xM{P(;dl0#NM#KdCrcs$c zHnPd_7a72JXR?@utN{J={-RVw5POXt(vOosCVyu#B#86Woh3D8gc%`{C>g zXXiqsQEi9OMKUSJ_V$U$iZID0Gg*+t6G*wfOtM&%zL;lmE^7l7uq@LW+k1<}U@+`C z{eipeIg7q~1e4+6aJjV1o&AI3v+*>2$i%Z^lfxfR%9h3&UchK<>?xRKsmSgiR@c?} zgv0KUw literal 0 HcmV?d00001 diff --git a/src/main/java/org/gcube/portal/databook/.DS_Store b/src/main/java/org/gcube/portal/databook/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..074316639a311351ef3ca995d9f2805a7d36aeed GIT binary patch literal 6148 zcmeHK%}T>S5Z-NT+falY6!aGGS}?^H4_-p7FJMFuDm5WNgE3o@v^|tU?)pN$h|lB9 z?gk77youNu*!|{rH~T^MhcU+8ML1&2WQ_HpA#zk21l^6HmQF_Ga*T*&!785zi3l17 z`in07_AbjAd^uZU|K8TER=cy)?e&b_pm*;*iIrFQ#Ugk8>=vynA(Eid z{op!|Rx@+&T%?5`r%@&g;xK}gyPG%-#mW_nG|XkKrvir2H)iJHdOaRbhSq3oZ-&-- zWS@dDIhkxWMt}e4`0R4_oV=vsRWZqdbSb+UD|iE?wy33-rHM!%!C%!>xrD?3F+dCu z16#*{J_`DSty?)Qm>3`ieqsRk2MZdaqp?&dw+`s=`i$`oA`0mEmO!*LIvPub5CP$; z6i}6N{lws^9Q>Bfb2OF;RXO8wW*A4$Ts>a6oE`j@OlRCtNIfw?4AdEDE7QdD{{nuQ z#z%g=ge+o!82D!l@Xpkmy09pHwtib4p0yUV2WTjmSE2#}dhHSb2JRyVGN|Gf>X7GX WEEVD?=$GYybP0t27W<4k`5 literal 0 HcmV?d00001 diff --git a/src/main/java/org/gcube/portal/databook/GCubeSocialNetworking.gwt.xml b/src/main/java/org/gcube/portal/databook/GCubeSocialNetworking.gwt.xml new file mode 100644 index 0000000..d40b2ea --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/GCubeSocialNetworking.gwt.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/gcube/portal/databook/client/GCubeSocialNetworking.java b/src/main/java/org/gcube/portal/databook/client/GCubeSocialNetworking.java new file mode 100644 index 0000000..565127d --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/client/GCubeSocialNetworking.java @@ -0,0 +1,17 @@ +package org.gcube.portal.databook.client; + +import com.google.gwt.core.client.EntryPoint; + +/** + * Entry point classes define onModuleLoad() and instances the HandlerManager for IPC + */ +public class GCubeSocialNetworking implements EntryPoint { + public static final String USER_PROFILE_OID = "userIdentificationParameter"; + public static final String HASHTAG_OID = "hashtagIdentificationParameter"; + public static final String SEARCH_OID = "elasticSearchIdentificationParameter"; + public static final String SHOW_STATISTICS_ACTION_OID = "showUserStatisticsActionParameter"; // see ShowUserStatisticAction + public static final String GROUP_MEMBERS_OID = "teamIdentificationParameter"; + public void onModuleLoad() { + } + +} diff --git a/src/main/java/org/gcube/portal/databook/client/util/Encoder.java b/src/main/java/org/gcube/portal/databook/client/util/Encoder.java new file mode 100644 index 0000000..312a720 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/client/util/Encoder.java @@ -0,0 +1,15 @@ +package org.gcube.portal.databook.client.util; +/** + * simply encode base64 strings + * @author massi + * + */ +public class Encoder { + public static native String encode(String toEncode) /*-{ + return btoa(toEncode); + }-*/; + + public static native String decode(String toDecode) /*-{ + return atob(toDecode); +}-*/; +} diff --git a/src/main/java/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java b/src/main/java/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java new file mode 100644 index 0000000..20724f1 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java @@ -0,0 +1,945 @@ +package org.gcube.portal.databook.server; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import javax.mail.internet.AddressException; + +import org.gcube.portal.databook.shared.*; +import org.gcube.portal.databook.shared.ex.ColumnNameNotFoundException; +import org.gcube.portal.databook.shared.ex.CommentIDNotFoundException; +import org.gcube.portal.databook.shared.ex.FeedIDNotFoundException; +import org.gcube.portal.databook.shared.ex.FeedTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.InviteIDNotFoundException; +import org.gcube.portal.databook.shared.ex.InviteStatusNotFoundException; +import org.gcube.portal.databook.shared.ex.LikeIDNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationChannelTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationIDNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.PrivacyLevelTypeNotFoundException; +import org.gcube.social_networking.social_networking_client_library.CommentClient; +import org.gcube.social_networking.social_networking_client_library.HashTagClient; +import org.gcube.social_networking.social_networking_client_library.InviteClient; +import org.gcube.social_networking.social_networking_client_library.LikeClient; +import org.gcube.social_networking.social_networking_client_library.NotificationClient; +import org.gcube.social_networking.social_networking_client_library.PostClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Massimiliano Assante ISTI-CNR + * @author Costantino Perciante ISTI-CNR + * This class is used for querying and adding data to Cassandra via Astyanax High Level API + */ +public final class DBCassandraAstyanaxImpl implements DatabookStore { + + /** + * logger + */ + private static final Logger _log = LoggerFactory.getLogger(DBCassandraAstyanaxImpl.class); + private static PostClient postClient; + private static NotificationClient notificationClient; + private static HashTagClient hashTagClient; + private static InviteClient inviteClient; + private static CommentClient commentClient; + private static LikeClient likeClient; + + + /** + * use this constructor carefully from test classes + * @param dropSchema set true if you want do drop the current and set up new one + */ + protected DBCassandraAstyanaxImpl(boolean dropSchema) { + try { + postClient = new PostClient(); + notificationClient = new NotificationClient(); + hashTagClient = new HashTagClient(); + commentClient = new CommentClient(); + inviteClient = new InviteClient(); + likeClient = new LikeClient(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + /** + * public constructor, no dropping schema is allowed + */ + public DBCassandraAstyanaxImpl() { + try { + postClient = new PostClient(); + notificationClient = new NotificationClient(); + hashTagClient = new HashTagClient(); + commentClient = new CommentClient(); + inviteClient = new InviteClient(); + likeClient = new LikeClient(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + /** + * public constructor, no dropping schema is allowed, infrastructureName is given. + */ + public DBCassandraAstyanaxImpl(String infrastructureName) { + try { + postClient = new PostClient(); + notificationClient = new NotificationClient(); + hashTagClient = new HashTagClient(); + commentClient = new CommentClient(); + inviteClient = new InviteClient(); + likeClient = new LikeClient(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /* + * + ********************** FRIENDSHIPS (CONNECTIONS) *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public boolean requestFriendship(String from, String to) { + return true; + } + /** + * {@inheritDoc} + */ + @Override + public boolean approveFriendship(String from, String to) { + return true; + } + /** + * {@inheritDoc} + */ + @Override + public boolean denyFriendship(String from, String to) { + return true; + } + /** + * {@inheritDoc} + */ + @Override + public List getFriends(String userid) { + ArrayList toReturn = new ArrayList(); + return toReturn; + } + /** + * {@inheritDoc} + */ + @Override + public List getPendingFriendRequests(String userid) { + ArrayList toReturn = new ArrayList(); + return toReturn; + } + /* + * + ********************** FEEDS *********************** + * + */ + + private static Post feed2post(Feed feed){ + Post post = new Post(feed.getKey(), PostType.valueOf(feed.getType().toString()), feed.getEntityId(), feed.getTime(), + feed.getVreid(), feed.getUri(), feed.getUriThumbnail(), feed.getDescription(), feed.getPrivacy(), + feed.getFullName(), feed.getEmail(), feed.getThumbnailURL(), feed.getCommentsNo(), + feed.getLikesNo(), feed.getLinkTitle(), feed.getLinkDescription(), feed.getLinkHost(), feed.isApplicationFeed(), feed.isMultiFileUpload()); + return post; + } + + private static Feed post2feed(Post post){ + Feed feed = new Feed(post.getKey(), FeedType.valueOf(post.getType().toString()), post.getEntityId(), post.getTime(), + post.getVreid(), post.getUri(), post.getUriThumbnail(), post.getDescription(), post.getPrivacy(), + post.getFullName(), post.getEmail(), post.getThumbnailURL(), post.getCommentsNo(), + post.getLikesNo(), post.getLinkTitle(), post.getLinkDescription(), post.getLinkHost(), post.isApplicationFeed(), post.isMultiFileUpload()); + return feed; + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean saveUserFeed(Feed post) { + return saveUserPost(feed2post(post)); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveUserPost(Post post) { + return postClient.saveUserPostLib(post); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean saveUserFeed(Feed feed, List attachments) { + return saveUserPost(feed2post(feed), attachments); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveUserPost(Post post, List attachments) { + return postClient.saveUserPostLib(post, attachments); + } + + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public boolean saveAppFeed(Feed post) { + return saveAppPost(feed2post(post)); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveAppPost(Post post) { + return postClient.saveAppPostLib(post); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean saveAppFeed(Feed feed, List attachments) { + return saveAppPost(feed2post(feed), attachments); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveAppPost(Post post, List attachments) { + return postClient.saveAppPostLib(post, attachments); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean saveFeedToVRETimeline(String feedKey, String vreid) throws FeedIDNotFoundException { + return savePostToVRETimeline(feedKey, vreid); + } + /** + * {@inheritDoc} + */ + @Override + public boolean savePostToVRETimeline(String postKey, String vreid) throws FeedIDNotFoundException { + return postClient.savePostToVRETimelineLib(postKey, vreid); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public Feed readFeed(String feedid) + throws PrivacyLevelTypeNotFoundException, + FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + + return post2feed(readPost(feedid)); + } + /** + * {@inheritDoc} + */ + @Override + public Post readPost(String postid) + throws PrivacyLevelTypeNotFoundException, + FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + return postClient.readPostLib(postid); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getRecentFeedsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException { + Date now = new Date(); + if (timeInMillis > now.getTime()) + throw new IllegalArgumentException("the timeInMillis must be before today"); + List posts = getRecentPostsByUserAndDate(userid, timeInMillis); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + */ + @Override + public List getRecentPostsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException { + Date now = new Date(); + if (timeInMillis > now.getTime()) + throw new IllegalArgumentException("the timeInMillis must be before today"); + + return postClient.getRecentPostsByUserAndDateLib(userid, timeInMillis); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean deleteFeed(String feedId) throws FeedIDNotFoundException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException { + return deletePost(feedId); + } + /** + * {@inheritDoc} + */ + @Override + public boolean deletePost(String postid) throws FeedIDNotFoundException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException { + return postClient.deletePostLib(postid); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public List getAllFeedsByUser(String userid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + List posts = getAllPostsByUser(userid); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + */ + @Override + public List getAllPostsByUser(String userid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getAllPostsByUserLib(userid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllFeedsByApp(String appid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + List posts = getAllPostsByApp(appid); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + */ + @Override + public List getAllPostsByApp(String appid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getAllPostsByAppLib(appid); + } + /** + * {@inheritDoc} + * @throws Exception + */ + @Deprecated + @Override + public List getRecentCommentedFeedsByUserAndDate(String userid, + long timeInMillis) throws Exception { + List posts = getRecentCommentedPostsByUserAndDate(userid, timeInMillis); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + * @throws Exception + */ + @Override + public List getRecentCommentedPostsByUserAndDate(String userid, + long timeInMillis) throws Exception { + return postClient.getRecentCommentedPostsByUserAndDateLib(userid, timeInMillis); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public List getAllPortalPrivacyLevelFeeds() throws FeedTypeNotFoundException, ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException { + List posts = getAllPortalPrivacyLevelPosts(); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + @Override + public List getAllPortalPrivacyLevelPosts() throws FeedTypeNotFoundException, ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException { + return postClient.getAllPortalPrivacyLevelPostsLib(); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getRecentFeedsByUser(String userid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + List posts = getRecentPostsByUser(userid, quantity); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + @Override + public List getRecentPostsByUser(String userid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getRecentPostsByUserLib(userid, quantity); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getAllFeedsByVRE(String vreid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + List posts = getAllPostsByVRE(vreid); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + */ + @Override + public List getAllPostsByVRE(String vreid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getAllPostsByVRELib(vreid); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public List getRecentFeedsByVRE(String vreid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + _log.info("\n\n in getRecentFeedsByVRE"); + List posts = getRecentPostsByVRE(vreid, quantity); + _log.info("length of vre posts = " + posts.size()); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + _log.info("length of vre feeds = " + feeds.size()); + return feeds; + } + @Override + public List getRecentPostsByVRE(String vreid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + _log.info("\n\n in getRecentPostsByVRE"); + return postClient.getRecentPostsByVRELib(vreid, quantity); + } + /** + * {@inheritDoc} + */ + @Override + public RangeFeeds getRecentFeedsByVREAndRange(String vreid, int from, int quantity) throws IllegalArgumentException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + RangePosts rangePosts = getRecentPostsByVREAndRange(vreid, from, quantity); + List posts = rangePosts.getPosts(); + ArrayList feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + RangeFeeds rangeFeeds = new RangeFeeds(rangePosts.getLastReturnedPostTimelineIndex(), feeds); + return rangeFeeds; + } + /** + * {@inheritDoc} + */ + @Override + public RangePosts getRecentPostsByVREAndRange(String vreid, int from, int quantity) throws IllegalArgumentException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getRecentPostsByVREAndRangeLib(vreid, from, quantity); + } + + /* + * + ********************** NOTIFICATIONS *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public boolean saveNotification(Notification n) { + return notificationClient.saveNotificationLib(n); + } + + /** + * {@inheritDoc} + */ + @Override + public Notification readNotification(String notificationid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.readNotificationLib(notificationid); + } + /** + * {@inheritDoc} + */ + @Override + public boolean setNotificationRead(String notificationidToSet) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.setNotificationReadLib(notificationidToSet); + } + + /** + * {@inheritDoc} + */ + @Override + public List getAllNotificationByUser(String userid, int limit) throws NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.getAllNotificationByUserLib(userid, limit); + } + /** + * {@inheritDoc} + */ + @Override + public List getUnreadNotificationsByUser(String userid) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException { + return notificationClient.getUnreadNotificationsByUserLib(userid); + } + /** + * {@inheritDoc} + */ + @Override + public List getRangeNotificationsByUser(String userid,int from, int quantity) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException { + return notificationClient.getRangeNotificationsByUserLib(userid, from, quantity); + } + /** + * {@inheritDoc} + */ + @Override + public boolean setAllNotificationReadByUser(String userid) throws NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.setAllNotificationReadByUserLib(userid); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean checkUnreadNotifications(String userid) throws NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.checkUnreadNotificationsLib(userid); + } + /** + * {@inheritDoc} + */ + @Override + public boolean checkUnreadMessagesNotifications(String userid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.checkUnreadMessagesNotificationsLib(userid); + } + /* + * + ********************** NOTIFICATION SETTINGS *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public List getUserNotificationChannels(String userid, NotificationType notificationType) throws NotificationChannelTypeNotFoundException, NotificationTypeNotFoundException { + return notificationClient.getUserNotificationChannelsLib(userid, notificationType); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean setUserNotificationPreferences(String userid, Map enabledChannels) { + return notificationClient.setUserNotificationPreferencesLib(userid, enabledChannels); + } + /** + * {@inheritDoc} + * + * by default Workspace and Calendar Notifications are set to Portal + */ + @Override + public Map getUserNotificationPreferences(String userid) throws NotificationTypeNotFoundException, NotificationChannelTypeNotFoundException { + return notificationClient.getUserNotificationPreferencesLib(userid); + } + /* + * + ********************** COMMENTS *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public boolean addComment(Comment comment) throws FeedIDNotFoundException { + return commentClient.addCommentLib(comment)!=null; + } + /** + * {@inheritDoc} + */ + public Comment readCommentById(String commentId) throws CommentIDNotFoundException { + return commentClient.readCommentByIdLib(commentId); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getAllCommentByFeed(String feedid) { + return getAllCommentByPost(feedid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllCommentByPost(String postid) { + return commentClient.getAllCommentsByPostIdLib(postid); + } + + /** + * {@inheritDoc} + * @throws Exception + */ + @Override + public List getRecentCommentsByUserAndDate(final String userid, + final long timeInMillis) throws Exception { + + return commentClient.getRecentCommentsByUserAndDateLib(userid, timeInMillis); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean editComment(Comment comment2Edit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, CommentIDNotFoundException, FeedIDNotFoundException { + return commentClient.editCommentLib(comment2Edit)!=null; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteComment(String commentid, String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, CommentIDNotFoundException, FeedIDNotFoundException { + return commentClient.deleteCommentLib(commentid, feedid); + } + /** + * {@inheritDoc} + */ + @Override + public boolean like(Like like) throws FeedIDNotFoundException { + return likeClient.likeLib(like); + } + /** + * {@inheritDoc} + */ + @Override + public boolean unlike(String userid, String likeid, String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, LikeIDNotFoundException, FeedIDNotFoundException { + return likeClient.unlikeLib(userid, likeid, feedid); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getAllLikedFeedIdsByUser(String userid) { + return getAllLikedPostIdsByUser(userid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllLikedPostIdsByUser(String userid) { + return likeClient.getAllLikedPostIdsByUserLib(userid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllLikedFeedsByUser(String userid, int limit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + ArrayList toReturn = new ArrayList<>(); + List likedPostIDs = getAllLikedPostIdsByUser(userid); + + //check if quantity is greater than user feeds + limit = (limit > likedPostIDs.size()) ? likedPostIDs.size() : limit; + + //need them in reverse order + for (int i = likedPostIDs.size()-1; i >= (likedPostIDs.size()-limit); i--) { + Feed toAdd = readFeed(likedPostIDs.get(i)); + if (toAdd.getType() == FeedType.TWEET || toAdd.getType() == FeedType.SHARE || toAdd.getType() == FeedType.PUBLISH) { + toReturn.add(toAdd); + _log.trace("Read recent post: " + likedPostIDs.get(i)); + } else { + _log.trace("Read and skipped post: " + likedPostIDs.get(i) + " (Removed post)"); + limit += 1; //increase the quantity in case of removed feed + //check if quantity is greater than user feeds + limit = (limit > likedPostIDs.size()) ? likedPostIDs.size() : limit; + } + } + return toReturn; + } + /** + * {@inheritDoc} + */ + @Override + public List getAllLikedPostsByUser(String userid, int limit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + ArrayList toReturn = new ArrayList(); + List likedPostIDs = getAllLikedPostIdsByUser(userid); + + //check if quantity is greater than user feeds + limit = (limit > likedPostIDs.size()) ? likedPostIDs.size() : limit; + + //need them in reverse order + for (int i = likedPostIDs.size()-1; i >= (likedPostIDs.size()-limit); i--) { + Post toAdd = readPost(likedPostIDs.get(i)); + if (toAdd.getType() == PostType.TWEET || toAdd.getType() == PostType.SHARE || toAdd.getType() == PostType.PUBLISH) { + toReturn.add(toAdd); + _log.trace("Read recent post: " + likedPostIDs.get(i)); + } else { + _log.trace("Read and skipped post: " + likedPostIDs.get(i) + " (Removed post)"); + limit += 1; //increase the quantity in case of removed feed + //check if quantity is greater than user feeds + limit = (limit > likedPostIDs.size()) ? likedPostIDs.size() : limit; + } + } + return toReturn; + } + + /** + * {@inheritDoc} + */ + @Override + public List getRecentLikedFeedsByUserAndDate(String userid, + long timeInMillis) throws IllegalArgumentException { + + List toReturn = new ArrayList<>(); + + Date now = new Date(); + if (timeInMillis > now.getTime()) + throw new IllegalArgumentException("the timeInMillis must be before today"); + + if(userid == null || userid.isEmpty()) + throw new IllegalArgumentException("the userId parameter cannot be null/empty"); + + // get the list of liked feeds + List likedPostsIdsByUser = getAllLikedFeedIdsByUser(userid); + + if(likedPostsIdsByUser != null && !likedPostsIdsByUser.isEmpty()){ + for(int i = likedPostsIdsByUser.size() - 1; i >= 0; i--){ + String postid = likedPostsIdsByUser.get(i); + try{ + + // retrieve the Post + Feed toCheck = readFeed(postid); + boolean isPostOk = (toCheck.getType() == FeedType.TWEET || toCheck.getType() == FeedType.SHARE || toCheck.getType() == FeedType.PUBLISH); + + // retrieve the like of the user for the post + if(isPostOk){ + List likes = getAllLikesByFeed(postid); + for (Like like : likes) { + if(like.getTime().getTime() >= timeInMillis && like.getUserid().equals(userid)) + toReturn.add(toCheck); + } + } + + }catch(Exception e){ + _log.error("Skipped post with id " + postid, e); + } + } + } + + // please check consider that if a user made like recently to an old post, well it could happen that this + // post comes first than a newer post in the toReturn list. Thus we need to sort it. + Collections.sort(toReturn, Collections.reverseOrder()); + + return toReturn; + + } + /** + * {@inheritDoc} + */ + @Override + public List getRecentLikedPostsByUserAndDate(String userid, + long timeInMillis) throws IllegalArgumentException { + + List toReturn = new ArrayList<>(); + + Date now = new Date(); + if (timeInMillis > now.getTime()) + throw new IllegalArgumentException("the timeInMillis must be before today"); + + if(userid == null || userid.isEmpty()) + throw new IllegalArgumentException("the userId parameter cannot be null/empty"); + + // get the list of liked feeds + List likedPostsIdsByUser = getAllLikedPostIdsByUser(userid); + + if(likedPostsIdsByUser != null && !likedPostsIdsByUser.isEmpty()){ + for(int i = likedPostsIdsByUser.size() - 1; i >= 0; i--){ + String postid = likedPostsIdsByUser.get(i); + try{ + + // retrieve the Post + Post toCheck = readPost(postid); + boolean isPostOk = (toCheck.getType() == PostType.TWEET || toCheck.getType() == PostType.SHARE || toCheck.getType() == PostType.PUBLISH); + + // retrieve the like of the user for the post + if(isPostOk){ + List likes = getAllLikesByPost(postid); + for (Like like : likes) { + if(like.getTime().getTime() >= timeInMillis && like.getUserid().equals(userid)) + toReturn.add(toCheck); + } + } + + }catch(Exception e){ + _log.error("Skipped post with id " + postid, e); + } + } + } + + // please check consider that if a user made like recently to an old post, well it could happen that this + // post comes first than a newer post in the toReturn list. Thus we need to sort it. + Collections.sort(toReturn, Collections.reverseOrder()); + + return toReturn; + } + + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public List getAllLikesByFeed(String feedid) { + return getAllLikesByPost(feedid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllLikesByPost(String postid) { + //possible error index + return likeClient.getAllLikesByPostLib(postid); + } + /* + * + ********************** HASHTAGS *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public boolean saveHashTags(String feedid, String vreid, List hashtags) throws FeedIDNotFoundException { + return hashTagClient.saveHashTagsLib(feedid, vreid, hashtags); + } + /** + * {@inheritDoc} + */ + @Override + public boolean deleteHashTags(String feedid, String vreid, List hashtags) throws FeedIDNotFoundException { + return hashTagClient.deleteHashTagsLib(feedid, vreid, hashtags); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveHashTagsComment(String commentId, String vreid, List hashtags) throws CommentIDNotFoundException { + return hashTagClient.saveHashTagsCommentLib(commentId, vreid, hashtags); + } + /** + * {@inheritDoc} + */ + @Override + public boolean deleteHashTagsComment(String commentId, String vreid, List hashtags) throws CommentIDNotFoundException { + return hashTagClient.deleteHashTagsCommentLib(commentId, vreid, hashtags); + } + /** + * {@inheritDoc} + */ + @Override + public Map getVREHashtagsWithOccurrence(String vreid) { + return hashTagClient.getVREHashtagsWithOccurrenceLib(vreid); + } + /** + * {@inheritDoc} + */ + @Override + public Map getVREHashtagsWithOccurrenceFilteredByTime(String vreid, long timestamp){ + return hashTagClient.getVREHashtagsWithOccurrenceFilteredByTimeLib(vreid, timestamp); + } + + /** + * {@inheritDoc} + */ + @Override + public List getVREFeedsByHashtag(String vreid, String hashtag) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + return null; + } + /** + * {@inheritDoc} + */ + @Override + public List getVREPostsByHashtag(String vreid, String hashtag) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + return hashTagClient.getVREPostsByHashtagLib(vreid, hashtag); + } + /* + * + ********************** Invites *********************** + * + */ + + + /** + * {@inheritDoc} + */ + @Override + public String isExistingInvite(String vreid, String email) { + return inviteClient.isExistingInviteLib(vreid, email); + } + /** + * {@inheritDoc} + */ + @Override + public InviteOperationResult saveInvite(Invite invite) throws AddressException { + return inviteClient.saveInviteLib(invite); + } + /** + * {@inheritDoc} + */ + @Override + public Invite readInvite(String inviteid) throws InviteIDNotFoundException, InviteStatusNotFoundException { + return inviteClient.readInviteLib(inviteid); + } + + /** + * {@inheritDoc} + * @throws InviteStatusNotFoundException + */ + @Override + public boolean setInviteStatus(String vreid, String email, InviteStatus status) throws InviteIDNotFoundException, InviteStatusNotFoundException { + return inviteClient.setInviteStatusLib(vreid, email, status); + } + /** + * {@inheritDoc} + */ + @Override + public List getInvitedEmailsByVRE(String vreid, InviteStatus... status) throws InviteIDNotFoundException, InviteStatusNotFoundException{ + return inviteClient.getInvitedEmailsByVRELib(vreid, status); + } + /** + * {@inheritDoc} + */ + @Override + public List getAttachmentsByFeedId(String feedId) throws FeedIDNotFoundException { + return postClient.getAttachmentsByFeedIdLib(feedId); + } + /** + * {@inheritDoc} + */ + @Override + public void closeConnection() { + } + + @Override + public List getAllVREIds(){ + return postClient.getAllVREIdsLib(); + } +} diff --git a/src/main/java/org/gcube/portal/databook/server/DatabookCassandraTest.java b/src/main/java/org/gcube/portal/databook/server/DatabookCassandraTest.java new file mode 100644 index 0000000..8d02836 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/server/DatabookCassandraTest.java @@ -0,0 +1,690 @@ +package org.gcube.portal.databook.server; +import java.util.UUID; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + + +public class DatabookCassandraTest { + private static DBCassandraAstyanaxImpl store; + + @BeforeClass + public static void setup() throws Exception { + store = new DBCassandraAstyanaxImpl(); //set to true if you want to drop the KeySpace and recreate it + } + + @AfterClass + public static void close(){ + store.closeConnection(); + System.out.println("End"); + + } + + // @Test + // public void getRecentCommentedFeedsByUserAndDate() throws Exception{ + // String userid = "massimiliano.assante"; + // Calendar oneYearAgo = Calendar.getInstance(); + // oneYearAgo.set(Calendar.YEAR, oneYearAgo.get(Calendar.YEAR) - 1); + // + // long init = System.currentTimeMillis(); + // List res = store.getRecentCommentedFeedsByUserAndDate(userid, oneYearAgo.getTimeInMillis()); + // long end = System.currentTimeMillis(); + // System.out.println("Result is " + (end - init)); + // + // + // } + // @Test + // public void getRecentCommentsByUserAndDate() throws Exception{ + // + // String userid = "costantino.perciante"; + // Calendar oneYearAgo = Calendar.getInstance(); + // oneYearAgo.set(Calendar.YEAR, oneYearAgo.get(Calendar.YEAR) - 1); + // + // List res = store.getRecentCommentsByUserAndDate(userid, oneYearAgo.getTimeInMillis()); + // + // for (Comment comment : res) { + // System.out.println("Result is " + comment); + // } + // + // + // + // + // } + // @Test + // public void getRecentLikedFeedsByUser(){ + // + // String userid = "costantino.perciante"; + // Calendar oneYearAgo = Calendar.getInstance(); + // oneYearAgo.set(Calendar.YEAR, oneYearAgo.get(Calendar.YEAR) - 1); + // + // List result = store.getRecentLikedFeedsByUserAndDate(userid, oneYearAgo.getTimeInMillis()); + // + // for (Feed feed : result) { + // System.out.println("Result is " + feed); + // } + // } + // @Test + // public void getHashTagsFilteredByTime() throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException{ + // + // int windowSize = 6; // go back windowSize months + // + // String vreUnderTest = "/gcube/devsec/devVRE"; + // + // // reference time + // Calendar calendar = Calendar.getInstance(); + // int currentMonth = calendar.get(Calendar.MONTH); // jan = 0, ..... dec = 11 + // calendar.set(Calendar.MONTH, currentMonth - windowSize); // the year is automatically decreased if needed + // SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + // System.out.println("Reference time for trending topics is " + format.format(calendar.getTime())); + // + // Map res = + // store.getVREHashtagsWithOccurrenceFilteredByTime( + // vreUnderTest, calendar.getTimeInMillis()); + // + // // find max score inside the list (counter) + // int max = 0; + // for(Entry entry : res.entrySet()){ + // + // max = max < entry.getValue() ? entry.getValue() : max; + // + // } + // + // // normalize + // Map normalized = new HashMap(); + // for(Entry entry : res.entrySet()){ + // + // normalized.put(entry.getKey(), (double)entry.getValue() / (double)max); + // + // } + // + // // create the weight for each entry as: + // // w = 0.6 * normalized_score + 0.4 * freshness + // // freshness is evaluated as (window_size - latest_feed_for_hashtag_in_window_month)/window_size + // Map scoredList = new HashMap(); + // for(Entry entry : res.entrySet()){ + // + // double weight = 0.6 * normalized.get(entry.getKey()); + // + // // retrieve the last feed for this hashtag and locate it into the window + // List mostRecentFeedForHashtag = store.getVREFeedsByHashtag(vreUnderTest, entry.getKey()); + // + // // retrieve the most recent one among these feeds + // Collections.sort(mostRecentFeedForHashtag, Collections.reverseOrder()); + // + // // locate into the window + // Calendar locateInWindow = Calendar.getInstance(); + // locateInWindow.setTimeInMillis(mostRecentFeedForHashtag.get(0).getTime().getTime()); + // + // // get the month + // int sub = currentMonth - locateInWindow.get(Calendar.MONTH); + // int value = sub >= 0? sub : 12 - Math.abs(sub); + // double freshness = (double)(windowSize - value) / (double)(windowSize); + // System.out.println("freshness is " + freshness + " because the last feed has month " + locateInWindow.get(Calendar.MONTH)); + // + // weight += 0.4 * freshness; + // + // scoredList.put(entry.getKey(), weight); + // } + // + // // print sorted + // Map scoredListSorted = sortByValue(scoredList); + // for(Entry entry : scoredListSorted.entrySet()){ + // + // System.out.println("[hashtag=" + entry.getKey() + " , weight=" + entry.getValue() + "]"); + // } + // } + // + // public static > Map + // sortByValue( Map map ) + // { + // List> list = + // new LinkedList>( map.entrySet() ); + // Collections.sort( list, new Comparator>() + // { + // public int compare( Map.Entry o1, Map.Entry o2 ) + // { + // return (o2.getValue()).compareTo( o1.getValue() ); + // } + // }); + // + // Map result = new LinkedHashMap(); + // for (Map.Entry entry : list) + // { + // result.put( entry.getKey(), entry.getValue() ); + // } + // return result; + // } + + + // @Test + // public void getHashTags() throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException{ + // List resList = store.getVREFeedsByHashtag("/gcube/devsec/devVRE", "#test"); + // + // for (Feed feed : resList) { + // System.out.println(feed.getTime()); + // } + // + // } + + // @Test + // public void getComment(){ + // + // String uuid = "820969b2-4632-4197-9fd6-5aafab781faa"; + // + // Comment c; + // try { + // c = store.readCommentById(uuid); + // System.err.println(c); + // } catch (CommentIDNotFoundException e) { + // // TODO Auto-generated catch block + // System.err.println(e.toString()); + // } + // } + + // @Test + // public void vreIds(){ + // + // try { + // List ids = store.getAllVREIds(); + // System.out.println(ids); + // } catch (ConnectionException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // + // } + + // @Test + // public void testFeedNumberPerUser() { + // String userid = "massimiliano.assante"; + // + // List feeds = null; + // int numComment = 0; + // long init = System.currentTimeMillis(); + // try { + // feeds = store.getAllFeedsByUser(userid); + // + // for (Feed feed : feeds) { + // List comments = store.getAllCommentByFeed(feed.getKey()); + // + // + // for (Comment comment : comments) { + // numComment ++; + // } + // } + // + // } catch (PrivacyLevelTypeNotFoundException | FeedTypeNotFoundException + // | ColumnNameNotFoundException | FeedIDNotFoundException e) { + // // TODO Auto-generated catch block + // System.err.println(e.toString()); + // } + // long end = System.currentTimeMillis(); + // System.err.println("retrieved " + feeds.size() + " and " + numComment + " in " + (end - init) + "ms"); + // } + + // @Test + // public void testAttachments() { + // Attachment a1 = new Attachment(UUID.randomUUID().toString(), "www1", "gattino1", "description1", "http://cdn.tuttozampe.com/wp-content/uploads/2010/09/ipoglicemia-gatto.jpg", "image/jpg"); + // Attachment a2 = new Attachment(UUID.randomUUID().toString(), "www2", "name2", "description2", "http://www.gcomegatto.it/wp-content/uploads/2015/01/09gatto.jpg","image/jpg"); + // Attachment a3 = new Attachment(UUID.randomUUID().toString(), "www3", "name3", "description3", "http://cdn.tuttozampe.com/wp-content/uploads/2010/09/ipoglicemia-gatto.jpg","image/jpg"); + // List toPass = new ArrayList(); + // toPass.add(a1); + // toPass.add(a2); + // toPass.add(a3); + // + // String feedId = UUID.randomUUID().toString(); + // Feed feed = new Feed(feedId, FeedType.TWEET, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "http://www.dailybest.it/wp-content/uploads/2015/10/gattini-nele-ciotole-e1344352237289.jpg", + // "http://www.dailybest.it/wp-content/uploads/2015/10/gattini-nele-ciotole-e1344352237289.jpg", + // "This post has attachments (gattini) ", PrivacyLevel.SINGLE_VRE, + // "Massimiliano Assante", + // "massimiliano.assante@isti.cnr.it", + // "http://www.dailybest.it/wp-content/uploads/2015/10/gattini-nele-ciotole-e1344352237289.jpg", + // "Gattino", + // "linkDesc", + // "image/jpeg", false); + // feed.setMultiFileUpload(true); + // assertTrue(store.saveUserFeed(feed, toPass)); + // System.out.println("Wrote post? "); + // System.out.println("Feed has the following attachments: "); + // try { + // for (Attachment at : store.getAttachmentsByFeedId(feedId)) { + // System.out.println(at); + // } + // } catch (FeedIDNotFoundException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // + // } + + // @Test + // public void testHashTag() { + // try { + // final String VREID = "/gcube/devsec/devVRE"; + // final String HASHTAG1 = "#testHashTag"; + // final String HASHTAG2 = "#testHashTag3"; + // List hashtags = new LinkedList(); + // hashtags.add(HASHTAG1); + // hashtags.add(HASHTAG2); + // + //// Feed feed = new Feed(UUID.randomUUID().toString(), FeedType.TWEET, "massimiliano.assante", new Date(), VREID, + //// "www.d4science.org/monitor", "thumbUri", "This is a feed with " + HASHTAG1 + " and " + HASHTAG2, PrivacyLevel.VRES, "Massimiliano Assante", "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host"); + //// assertTrue(store.saveUserFeed(feed)); + //// assertTrue(store.saveHashTags(feed.getKey(), VREID, hashtags)); + //// assertTrue(store.deleteHashTags("d0c64e42-9616-4e24-a65a-7a63a280d676", VREID, hashtags)); + //// System.out.println(feed); + //// + // System.out.println("\ngetting getVREHashtagsWithOccurrence for " + VREID); + // Map hashtagsWithOcc = store.getVREHashtagsWithOccurrence(VREID); + // for (String hashtag : hashtagsWithOcc.keySet()) { + // System.out.println(hashtag + ":" + hashtagsWithOcc.get(hashtag)); + // } + // + // System.out.println("\ngetting getVREFeedsByHashtag for " + VREID + " and " + HASHTAG1); + // for (Feed theFeed : store.getVREFeedsByHashtag(VREID, HASHTAG1)) { + // System.out.println(theFeed); + // } + // + // } catch (Exception e) { + // e.printStackTrace(); + // } + // + // + // } + + +// /** +// * use exclusively to add a new (Static) CF to a keyspace with a secondary index +// */ +// @Test +// public void addAttachmentStaticColumnFamilies() { +// ColumnFamily CF_ATTACHMENTS = ColumnFamily.newColumnFamily(DBCassandraAstyanaxImpl.ATTACHMENTS, StringSerializer.get(), StringSerializer.get()); +// +// try { +// String colNameToIndex = "feedId"; +// new CassandraClusterConnection(false).getKeyspace().createColumnFamily(CF_ATTACHMENTS, ImmutableMap.builder() +// .put("column_metadata", ImmutableMap.builder() +// .put(colNameToIndex, ImmutableMap.builder() +// .put("validation_class", "UTF8Type") +// .put("index_name", "FeedIndex_"+UUID.randomUUID().toString().substring(0,5)) +// .put("index_type", "KEYS") +// .build()) +// .build()) +// .build()); +// +// +// } catch (ConnectionException e) { +// e.printStackTrace(); +// } +// System.out.println("addStaticColumnFamily END"); +// } +// + +// /** +// * use exclusively to add a new (Dynamic) CF to a keyspace +// */ +// @Test +// public void addInvitesDynamicColumnFamilies() { +// System.out.println("UserNotificationsUnread"); +// ColumnFamily cf_UserNotificationsUnreadTimeline = new ColumnFamily( +// DBCassandraAstyanaxImpl.EMAIL_INVITES, // Column Family Name +// StringSerializer.get(), // Key Serializer +// StringSerializer.get()); // Column Serializer +// +// try { +// +// new CassandraClusterConnection(false).getKeyspace().createColumnFamily(cf_UserNotificationsUnreadTimeline, ImmutableMap.builder() +// .put("default_validation_class", "UTF8Type") +// .put("key_validation_class", "UTF8Type") +// .put("comparator_type", "UTF8Type") +// .build()); +// +// } catch (ConnectionException e) { +// e.printStackTrace(); +// } +// System.out.println("UserNotificationsUnread END"); +// } + + + // private List getKeys() { + // List toReturn = new ArrayList(); + // try { + // + // OperationResult> rows = store.getConnection().getKeyspace().prepareQuery(DBCassandraAstyanaxImpl.cf_UserNotificationsPreferences) + // .getAllRows() + // .setRowLimit(1000) // This is the page size + // .execute(); + // int i = 1; + // for (Row row : rows.getResult()) { + // System.out.println(i+" ROW: " + row.getKey() + " " + row.getColumns().size()); + // toReturn.add(row.getKey()); + // i++; + // } + // } catch (ConnectionException e) { + // e.printStackTrace(); + // } + // return toReturn; + // } + // + // @Test + // public void testUserNotificationPreferences() { + // System.out.println("Notification type" + NotificationType.POST_ALERT.toString() +" OFF for:"); + // try { + // for (String user : getKeys()) { + // List channels = store.getUserNotificationChannels(user, NotificationType.POST_ALERT); + // if (channels.isEmpty()) { + // System.out.println(user); + // } + // else if (! channels.contains(NotificationChannelType.EMAIL)) { + // System.out.println(user + "->" + channels.toString()); + // } + // } + + + // for (NotificationChannelType channel : store.getUserNotificationChannels("roberto.trasarti", NotificationType.POST_ALERT)) { + // System.out.println(channel); + // } + // } catch (NotificationChannelTypeNotFoundException e) { + // e.printStackTrace(); + // } catch (NotificationTypeNotFoundException e) { + // e.printStackTrace(); + // }; + // + // } + + // @Test + // public void testLikes() { + // int count = 10; + // Feed feed = new Feed(UUID.randomUUID().toString(), FeedType.SHARE, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "http://www.d4science.org/monitor", "thumbUri", "This feed is Liked ", PrivacyLevel.PUBLIC, + // "Massimiliano Assante", "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host", false); + // assertTrue(store.saveUserFeed(feed)); + // Like toUnlike = new Like(UUID.randomUUID().toString(),"massimiliano.assante", + // new Date(), feed.getKey().toString(), "Massi Pallino", "thumbUrl"); + // + // try { + // assertTrue(store.like(toUnlike)); + // for (int i = 0; i < count; i++) + // assertTrue(store.like(new Like(UUID.randomUUID().toString(),"massimiliano.assante", + // new Date(), feed.getKey().toString(), "Rino Pallino", "thumbUrl"))); + // + // System.out.println("massimiliano.assante liked the following feeds: "); + // for (String feedid : store.getAllLikedFeedIdsByUser("massimiliano.assante")) { + // System.out.println(feedid); + // } + // + // for (Like like : store.getAllLikesByFeed(feed.getKey().toString())) { + // System.out.println(like); + // } + // System.out.println("massimiliano.assante trying unlike the following feed: " + toUnlike); + // store.unlike("massimiliano.assante", toUnlike.getKey(), toUnlike.getFeedid()); + // + // } catch (Exception e) { + // System.out.println("Exception feed id not found"); + // } + // } + // /** + // * use exclusively to add a new CF to a keyspace + // */ + // @Test + // public void addNotifPreferencesColumnFamily() { + // // ColumnFamily cf_UserNotificationsPreferences = new ColumnFamily( + // // DBCassandraAstyanaxImpl.USER_NOTIFICATIONS_PREFERENCES, // Column Family Name + // // StringSerializer.get(), // Key Serializer + // // StringSerializer.get()); // Column Serializer + // // + // // try { + // // new CassandraClusterConnection(false).getKeyspace().createColumnFamily(cf_UserNotificationsPreferences, ImmutableMap.builder() + // // .put("default_validation_class", "UTF8Type") + // // .put("key_validation_class", "UTF8Type") + // // .put("comparator_type", "UTF8Type") + // // .build()); + // // } catch (ConnectionException e) { + // // e.printStackTrace(); + // // } + // } + // + // @Test + // public void testFriendships() { + // assertTrue(store.requestFriendship("massimiliano.assante", "leonardo.candela")); + // assertTrue(store.requestFriendship("massimiliano.assante", "ermit")); + // assertTrue(store.requestFriendship("massimiliano.assante", "giorgino")); + // assertTrue(store.requestFriendship("barabba", "massimiliano.assante")); + // + // assertTrue(store.approveFriendship("leonardo.candela", "massimiliano.assante")); + // assertTrue(store.approveFriendship("ermit", "massimiliano.assante")); + // + // assertTrue(store.denyFriendship("giorgino", "massimiliano.assante")); + // System.out.println("Pending Connections for massimiliano.assante:"); + // for (String userid: store.getPendingFriendRequests("massimiliano.assante")) { + // System.out.println(userid); + // } + // + // System.out.println("Connections for massimiliano.assante:"); + // for (String userid: store.getFriends("massimiliano.assante")) { + // System.out.println(userid); + // } + // + // } + // @Test + // public void testLikedFeedsRetrieval() { + // try { + // for (Feed feed : store.getAllLikedFeedsByUser("luca.frosini", 10)) { + // System.out.println(feed); + // } + // } catch (Exception e) { + // e.printStackTrace(); + // } + // } + // + // + // + // + // @Test + // public void testSingleNotification() { + // Notification not = new Notification( + // UUID.randomUUID().toString(), + // NotificationType.LIKE, + // "leonardo.candela", + // "MESSAGEID", + // new Date(), + // "uri", + // "This is notification about a like", + // false, + // "leonardo.candela", "Leonardo Candela", + // "thumburl"); + // assertTrue(store.saveNotification(not)); + // + // not = new Notification( + // UUID.randomUUID().toString(), + // NotificationType.MESSAGE, + // "massimiliano.assante", + // "MESSAGEID", + // new Date(), + // "uri", + // "This is notification about a like", + // false, + // "antonio.gioia", "Antonio Gioia", + // "thumburl"); + // assertTrue(store.saveNotification(not)); + // System.out.println("Writing one Notification " + not); + // } + // + // @Test + // public void testNotifications() { + // Notification not = null; + // System.out.println("Writing 18 Notifications"); + // int count = 18; + // for (int i = 0; i < count; i++) { + // if (i % 2 != 0) { + // not = new Notification(UUID.randomUUID().toString(), NotificationType.JOB_COMPLETED_OK, + // "leonardo.candela", "TWEETID", new Date(), "uri", "This is notification about job completed OK #"+i, false, "pasquale.pagano", "Pasquale Pagano", "thumburl"); + // } else { + // not = new Notification(UUID.randomUUID().toString(), NotificationType.JOB_COMPLETED_NOK, + // "massimiliano.assante", "MESSAGEID", new Date(), "uri", "This is notification about completed NOK #"+i, false, "leonardo.candela", "Leonardo Candela", "thumburl"); + // } + // assertTrue(store.saveNotification(not)); + // try { + // Thread.sleep(150); + // } catch (InterruptedException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // } + // + // Notification rNot= null; + // try { + // + // //read + // rNot = store.readNotification(not.getKey().toString()); + // assertNotNull(rNot); + // System.out.println("Reading one Notification " + rNot.getKey() + ": " + rNot.getDescription() + " Type: " + rNot.getType()); + // + // //set Read + // assertTrue(store.setNotificationRead(rNot.getKey().toString())); + // + // System.out.println("Notification " + rNot.getKey() + " of Type: " + rNot.getType() + " was set to READ"); + // + // not = new Notification(UUID.randomUUID().toString(), NotificationType.LIKE, + // "leonardo.candela", "FEEDID", new Date(), "uri", "This is notification of a Liked Leo feed by Massi", false, "massimiliano.assante", "Massimiliano Assante", "thumburl"); + // assertTrue(store.saveNotification(not)); + // try { + // Thread.sleep(150); + // } catch (InterruptedException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // rNot = store.readNotification(not.getKey().toString()); + // System.out.println("Reading another Notification " + rNot.getKey() + " of Type: " + rNot.getType() + " Read:? " + rNot.isRead()); + // // //set Read + // // assertTrue(store.setNotificationRead(rNot.getKey().toString())); + // // System.out.println("Notification " + rNot.getKey() + " of Type: " + rNot.getType() + " was set to READ subject was this: " + rNot.getSubjectid()); + // // + // Random randomGenerator = new Random(); + // + // System.out.println("leonardo.candela Notifications: "); + // List recentNots = store.getAllNotificationByUser("leonardo.candela", randomGenerator.nextInt(50)); + // assertNotNull(recentNots); + // for (Notification notif :recentNots) + // System.out.println(notif); + // + // + // System.out.println("massimiliano.assante Notifications: "); + // recentNots = store.getUnreadNotificationsByUser("massimiliano.assante"); + // assertNotNull(recentNots); + // for (Notification notif :recentNots) + // System.out.println(notif); + // } catch (Exception e) { + // e.printStackTrace(); + // } + // + // System.out.println("getRangeNotificationsByUser massimiliano.assante: "); + // try { + // int from = 0; + // for (int i = 0; i < 5; i++) { + // System.out.println("\nFROM="+from); + // List range = store.getRangeNotificationsByUser("massimiliano.assante", from, 50); + // for (Notification notification : range) { + // System.out.println(notification.getDescription()); + // from = 1+i * 50; + // } + // } + // } catch (Exception e) { + // e.printStackTrace(); + // } + // } + // + // + // @Test + // public void testFeeds() { + // int count = 18; + // Feed feed = null; + // for (int i = 0; i < count; i++) { + // if (i % 2 != 0) { + // feed = new Feed(UUID.randomUUID().toString(), FeedType.JOIN, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "www.d4science.org/monitor", "thumbUri", "This is feed# "+ i, PrivacyLevel.VRES, "Massimiliano Assante", "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host"); + // } else { + // feed = new Feed(UUID.randomUUID().toString(), FeedType.TWEET, "leonardo.candela", new Date(), "", + // "www.d4science.org/web/guest", "thumbUri", "This is feed# "+ i, PrivacyLevel.PORTAL, "Leonardo Candela", "leonardo.candela@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host"); + // } + // assertTrue(store.saveUserFeed(feed)); + // try { + // Thread.sleep(150); + // } catch (InterruptedException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // } + // + // Feed rFeed = null; + // try { + // rFeed = store.readFeed(feed.getKey().toString()); + // rFeed = store.readFeed(feed.getKey().toString()); + // rFeed = store.readFeed(feed.getKey().toString()); + // rFeed = store.readFeed(feed.getKey().toString()); + // assertNotNull(rFeed); + // + // String feedIdToDelete = UUID.randomUUID().toString(); + // feed = new Feed(feedIdToDelete, FeedType.PUBLISH, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "www.d4science.org/monitor", "thumbUri", "This is feed to be deleted", PrivacyLevel.VRES, "Massimiliano Assante", "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host", false); + // assertTrue(store.saveUserFeed(feed)); + // try { + // Thread.sleep(250); + // } catch (InterruptedException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // System.out.println("Test Delete Feed "); + // assertTrue(store.deleteFeed(feedIdToDelete)); + // + // System.out.println("massimiliano.assante ALL FEEDS: "); + // for (Feed recFeed : store.getAllFeedsByUser("massimiliano.assante")) + // System.out.println(recFeed); + // } + // catch (Exception e) { + // e.printStackTrace(); + // } + // } + // + // + // + // @Test + // public void testComments() { + // int count = 10; + // Feed feed = new Feed(UUID.randomUUID().toString(), FeedType.SHARE, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "http://www.d4science.org/monitor", "thumbUri", "This is feed that is going to be commented ", PrivacyLevel.PUBLIC, "Massimiliano Assante", + // "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host", false); + // assertTrue(store.saveUserFeed(feed)); + // + // Comment toDelete = null; + // for (int i = 0; i < count; i++) { + // try { + // toDelete = new Comment(UUID.randomUUID().toString(),"leonardo.candela", + // new Date(), feed.getKey().toString(), "This comment #"+i, "Leonardo Candela", "thumbUrl"); + // assertTrue(store.addComment(toDelete)); + // + // } catch (FeedIDNotFoundException e) { + // System.out.println("Exception feed id not found"); + // } + // } + // System.out.println("GetAllCOmmentsByFeed "); + // for (Comment cm : store.getAllCommentByFeed(feed.getKey().toString())) { + // try { + // System.out.println(store.readCommentById(cm.getKey())); + // } catch (CommentIDNotFoundException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // }; + // + // try { + // assertTrue(store.deleteComment(toDelete.getKey(), toDelete.getFeedid())); + // } catch (Exception e) { + // System.out.println("Exception feed id not found"); + // } + // } + + +} diff --git a/src/main/java/org/gcube/portal/databook/server/DatabookStore.java b/src/main/java/org/gcube/portal/databook/server/DatabookStore.java new file mode 100644 index 0000000..95af072 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/server/DatabookStore.java @@ -0,0 +1,667 @@ +package org.gcube.portal.databook.server; + +import java.util.List; +import java.util.Map; + +import javax.mail.internet.AddressException; + +import org.gcube.portal.databook.shared.Attachment; +import org.gcube.portal.databook.shared.Comment; +import org.gcube.portal.databook.shared.Feed; +import org.gcube.portal.databook.shared.Invite; +import org.gcube.portal.databook.shared.InviteOperationResult; +import org.gcube.portal.databook.shared.InviteStatus; +import org.gcube.portal.databook.shared.Like; +import org.gcube.portal.databook.shared.Notification; +import org.gcube.portal.databook.shared.NotificationChannelType; +import org.gcube.portal.databook.shared.NotificationType; +import org.gcube.portal.databook.shared.Post; +import org.gcube.portal.databook.shared.RangeFeeds; +import org.gcube.portal.databook.shared.RangePosts; +import org.gcube.portal.databook.shared.ex.ColumnNameNotFoundException; +import org.gcube.portal.databook.shared.ex.CommentIDNotFoundException; +import org.gcube.portal.databook.shared.ex.FeedIDNotFoundException; +import org.gcube.portal.databook.shared.ex.FeedTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.InviteIDNotFoundException; +import org.gcube.portal.databook.shared.ex.InviteStatusNotFoundException; +import org.gcube.portal.databook.shared.ex.LikeIDNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationChannelTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationIDNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.PrivacyLevelTypeNotFoundException; + +/** + * @author Massimiliano Assante ISTI-CNR + * @author Costantino Perciante ISTI-CNR + * DatabookStore is the high level interface for querying and adding data to DatabookStore + */ +public interface DatabookStore { + /** + * userid from requests a friendship to userid to + * @return true if everything went fine + */ + boolean requestFriendship(String from, String to); + /** + * userid from approves a friendship to userid to + * @return true if everything went fine + */ + boolean approveFriendship(String from, String to); + /** + * userid from denies a friendship to userid to + * @return true if everything went fine + */ + boolean denyFriendship(String from, String to); + /** + * @param userid the user id you want to know friends + * @return a List of userid representing the friends for the given userid + */ + List getFriends(String userid); + /** + * @param userid the user id you want to know the pending friend requests + * @return a List of userid representing the friends for the given userid + */ + List getPendingFriendRequests(String userid); + /** + * @deprecated use saveUserPost + * save a Feed instance in the store + * @return true if everything went fine + */ + boolean saveUserFeed(Feed feed); + /** + * save a Post instance in the store + * @return true if everything went fine + */ + boolean saveUserPost(Post feed); + /** + * Save a Feed instance in the store having more than one attachment + * Use this if you need to attach more than one file to the post + * + * @deprecated use saveUserPost + * @param attachments a list of attachments starting from the second + * @return true if everything went fine + */ + boolean saveUserFeed(Feed feed, List attachments); + /** + * Save a Post instance in the store having more than one attachment + * Use this if you need to attach more than one file to the post + * + * @param attachments a list of attachments starting from the second + * @return true if everything went fine + */ + boolean saveUserPost(Post post, List attachments); + /** + * Delete a Feed from the store + * @deprecated use saveUserPost + * @throws FeedIDNotFoundException + * @return true if everything went fine + */ + boolean deleteFeed(String feedid) throws FeedIDNotFoundException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException; + /** + * delete a Feed from the store + * @throws FeedIDNotFoundException + * @return true if everything went fine + */ + boolean deletePost(String postid) throws FeedIDNotFoundException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException; + /** + * Save a post in the VRES TimeLine in the store + * @deprecated use savePostToVRETimeline + * @param feedKey feedKey + * @param vreid vre identifier + * @throws FeedIDNotFoundException + */ + boolean saveFeedToVRETimeline(String feedKey, String vreid) throws FeedIDNotFoundException; + /** + * save a post in the VRES TimeLine in the store + * @param postKey the post id + * @param vreid vre identifier + * @throws FeedIDNotFoundException + */ + boolean savePostToVRETimeline(String postKey, String vreid) throws FeedIDNotFoundException; + /** + * @deprecated use saveAppPost + * save a Post instance in the store + * @return true if everything went fine + */ + boolean saveAppFeed(Feed feed); + /** + * save a Post instance in the store + * @return true if everything went fine + */ + boolean saveAppPost(Post feed); + /** + * @deprecated use saveAppPost + * Save a Post instance in the store + * Use this if your app needs to attach more than one file to the post + * + * @param attachments a list of attachments starting from the second + * @return true if everything went fine + */ + boolean saveAppFeed(Feed feed, List attachments); + /** + * Save a Post instance in the store + * Use this if your app needs to attach more than one file to the post + * + * @param attachments a list of attachments starting from the second + * @return true if everything went fine + */ + boolean saveAppPost(Post feed, List attachments); + /** + * @deprecated use readPost + * read a feed from a given id + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + Feed readFeed(String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * read a feed from a given id + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + Post readPost(String postid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @deprecated use getAllPostsByUser instead + * @param userid user identifier + * return all the feeds belonging to the userid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllFeedsByUser(String userid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @param userid user identifier + * return all the feeds belonging to the userid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllPostsByUser(String userid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @deprecated use getAllPostsByApp instead + * @param appid application identifier + * return all the feeds belonging to the appid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllFeedsByApp(String appid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @param appid application identifier + * return all the feeds belonging to the appid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllPostsByApp(String appid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @deprecated use getRecentCommentedPostsByUserAndDate instead + * @param userid the user identifier like andrea.rossi + * @param timeInMillis the initial time in millis to be considered + * @return a list of feeds commented by userid starting from timeInMillis + * @throws Exception + */ + List getRecentCommentedFeedsByUserAndDate(String userid, long timeInMillis) throws Exception; + /** + * @param userid the user identifier like andrea.rossi + * @param timeInMillis the initial time in millis to be considered + * @return a list of feeds commented by userid starting from timeInMillis + * @throws Exception + */ + List getRecentCommentedPostsByUserAndDate(String userid, long timeInMillis) throws Exception; + /** + * @deprecated use getAllPortalPrivacyLevelPosts instead + * return all the feeds whose Level is PORTAL + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + * @throws PrivacyLevelTypeNotFoundException + */ + List getAllPortalPrivacyLevelFeeds() throws FeedTypeNotFoundException, ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException; + /** + * return all the feeds whose Level is PORTAL + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + * @throws PrivacyLevelTypeNotFoundException + */ + List getAllPortalPrivacyLevelPosts() throws FeedTypeNotFoundException, ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException; + + /** + * return the most recent feeds for this user up to quantity param + * @deprecated + * @param userid user identifier + * @param quantity the number of most recent feeds for this user + * @return a List of most recent feeds for this user + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getRecentFeedsByUser(String userid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * return the most recent feeds for this user up to quantity param + * @param userid user identifier + * @param quantity the number of most recent feeds for this user + * @return a List of most recent feeds for this user + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getRecentPostsByUser(String userid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * @deprecated use getAllPostsByVRE + * @param vreid vre identifier + * return all the feeds belonging to the userid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllFeedsByVRE(String vreid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * @param vreid vre identifier + * return all the feeds belonging to the userid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllPostsByVRE(String vreid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + + /** + * @deprecated use getRecentPostsByVRE + * return the most recent feeds for this vre up to quantity param + * @param vreid VRES identifier + * @param quantity the number of most recent feeds for this vre + * @return a List of most recent feeds for this vre + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getRecentFeedsByVRE(String vreid, int quantity) throws IllegalArgumentException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * return the most recent posts for this vre up to quantity param + * @param vreid VRES identifier + * @param quantity the number of most recent posts for this vre + * @return a List of most recent posts for this vre + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getRecentPostsByVRE(String vreid, int quantity) throws IllegalArgumentException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + + /** + * return the most recent posts for this vre up to quantity param and the last index of the feeds in the timeline + * lastReturnedFeedTimelineIndex is usuful to know from where to start the range the second time you ask + * because there are deletions + * + * @deprecated use getRecentPostsByVREAndRange + * @param vreid VRES identifier + * @param from the range start (most recent feeds for this vre) has to be greater than 0 + * @param quantity the number of most recent feeds for this vre starting from "from" param + * @return a lastReturnedFeedTimelineIndex containing of most recent feeds for this vre + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + RangeFeeds getRecentFeedsByVREAndRange(String vreid, int from, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * return the most recent posts for this vre up to quantity param and the last index of the posts in the timeline + * lastReturnedPostTimelineIndex is useful to know from where to start the range the next time you ask, because there are deletions + * + * @param vreid VRES identifier + * @param from the range start (most recent feeds for this vre) has to be greater than 0 + * @param quantity the number of most recent feeds for this vre starting from "from" param + * @return a RangePosts containing of most recent feeds for this vre + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + RangePosts getRecentPostsByVREAndRange(String vreid, int from, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + + /** + * @deprecated use getRecentPostsByUserAndDate + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return the number of feeds in the range from: today to: timeInMillis + */ + List getRecentFeedsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException; + /** + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return the number of feeds in the range from: today to: timeInMillis + */ + List getRecentPostsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException; + /** + * save a Notification instance in the store + * @return true if everything went fine + */ + boolean saveNotification(Notification notification); + /** + * set an existing Notification instance in the to read + * @return true if everything went fine + */ + boolean setNotificationRead(String notificationidToSet) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + /** + * read a notification from a given id + * @throws {@link ColumnNameNotFoundException} + * @throws {@link NotificationIDNotFoundException} + * @throws {@link NotificationTypeNotFoundException} + */ + Notification readNotification(String notificationid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + + /** + * @param userid user identifier + * @param limit set 0 to get everything, an int to get the most recent -limit- notifications + * return all the notifications belonging to the userid up to limit, set 0 to get everything + * @throws NotificationTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllNotificationByUser(String userid, int limit) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException; + /** + * + * @param userid user identifier + * @param from the range start has to be greater than 0 + * @param quantity the number of most recent notifications for this user starting from "from" param + * @return all the notifications for the userid in the range requested + * @throws NotificationTypeNotFoundException + * @throws ColumnNameNotFoundException + * @throws NotificationIDNotFoundException + */ + List getRangeNotificationsByUser(String userid, int from, int quantity) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException; + /** + * This is a fast way to set all notification to read quickly + * @param userid + * @return true if everything went fine + * @throws {@link ColumnNameNotFoundException} + * @throws {@link NotificationIDNotFoundException} + * @throws {@link NotificationTypeNotFoundException} + */ + boolean setAllNotificationReadByUser(String userid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + /** + * return the not yet read notifications (not including messages) + * @param userid user identifier + * @return a List of not yet read notifications for this user + * @throws NotificationTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getUnreadNotificationsByUser(String userid) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException; + /** + * + * @param userid user identifier + * @throws ColumnNameNotFoundException + * @throws NotificationTypeNotFoundException + * @throws NotificationIDNotFoundException + * @return true if there are unread notifications (not including messages), false if they are all read + */ + boolean checkUnreadNotifications(String userid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + /** + * + * @param userid user identifier + * @throws ColumnNameNotFoundException + * @throws NotificationTypeNotFoundException self explaining + * @throws NotificationChannelTypeNotFoundException self explaining + * @throws NotificationIDNotFoundException + * @return true if there are unread messages notifications (including messages), false if they are all read + */ + boolean checkUnreadMessagesNotifications(String userid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + + /** + * return the channels a user chose for being notified for a given notification type + * @param userid user identifier + * @param notificationType the type of the notification + * @return a list of NotificationChannelType that represents the channels this user wants to be notified + */ + List getUserNotificationChannels(String userid, NotificationType notificationType) throws NotificationChannelTypeNotFoundException, NotificationTypeNotFoundException; + /** + * set the notification preferences map (enable or disable the channels to be used for notifying the user) + * @param userid user identifier + * @param enabledChannels a map of the channels to which reach the user per notification, empty array or null values to set the key notification type off + * @return true if everything was fine + */ + boolean setUserNotificationPreferences(String userid, Map enabledChannels); + /** + * get the notification preferences map (enableor disable the channels to be used for notifying the user) + * @param userid user identifier + * @return the map + * @throws NotificationTypeNotFoundException self explaining + * @throws NotificationChannelTypeNotFoundException self explaining + */ + Map getUserNotificationPreferences(String userid) throws NotificationTypeNotFoundException, NotificationChannelTypeNotFoundException; + + /** + * @param commentId comment unique identifier + * @return the comment belonging to the commentId + * @throws CommentIDNotFoundException + */ + Comment readCommentById(String commentId) throws CommentIDNotFoundException; + /** + * add a comment to a feed + * @param comment the Comment instance to add + */ + boolean addComment(Comment comment) throws FeedIDNotFoundException; + /** + * @deprecated use getAllCommentByPost + * @param feedid feed identifier + * return all the comments belonging to the feedid + */ + List getAllCommentByFeed(String feedid); + /** + * @param postid the post identifier + * return all the comments belonging to the postid + */ + List getAllCommentByPost(String postid); + /** + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return a list of comments (sorted starting from the most recent one) made by the user since timeInMillis up to now + */ + List getRecentCommentsByUserAndDate(String userid, long timeInMillis) throws Exception; + /** + * edit a comment + * @param comment the comment to edit + * @return true if success, false otherwise + */ + boolean editComment(Comment comment) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, CommentIDNotFoundException, FeedIDNotFoundException; + /** + * deletes a comment + * @param commentid the comment identifier to delete + * @param feedid the feedid to which the comment is associated + * @return true if success, false otherwise + */ + boolean deleteComment(String commentid, String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, CommentIDNotFoundException, FeedIDNotFoundException; + /** + * add a like to a feed + * @param like instance + * @throws FeedIDNotFoundException + */ + boolean like(Like like) throws FeedIDNotFoundException; + /** + * unlike a feed + * @param userid user identifier + * @param likeid the like identifier to delete + * @param feedid the feedid to which the comment is associated + * @return true if success, false otherwise + */ + boolean unlike(String userid, String likeid, String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, LikeIDNotFoundException, FeedIDNotFoundException; + /** + * @deprecated use getAllLikedPostIdsByUser + * @param userid user identifier + * return all the feedids a user has liked + */ + List getAllLikedFeedIdsByUser(String userid); + /** + * @param userid user identifier + * return all the feedids a user has liked + */ + List getAllLikedPostIdsByUser(String userid); + /** + * @deprecated use getAllLikedPostsByUser + * @param userid user identifier + * @param limit set 0 to get everything, an int to get the most recent -limit- liked feeds + * @throws ColumnNameNotFoundException . + * @throws FeedIDNotFoundException . + * @throws FeedTypeNotFoundException . + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedIDNotFoundException . + * return all the feeds a user has liked + */ + List getAllLikedFeedsByUser(String userid, int limit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + + /** + * @param userid user identifier + * @param limit set 0 to get everything, an int to get the most recent -limit- liked posts + * @throws ColumnNameNotFoundException . + * @throws FeedIDNotFoundException . + * @throws FeedTypeNotFoundException . + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedIDNotFoundException . + * return all the feeds a user has liked + */ + List getAllLikedPostsByUser(String userid, int limit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + + /** + * @deprecated use getRecentLikedPostsByUserAndDate + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return the likes made to feeds in the range from: today to: timeInMillis + */ + List getRecentLikedFeedsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException; + /** + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return the likes made to feeds in the range from: today to: timeInMillis + */ + List getRecentLikedPostsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException; + /** + * @deprecated use getAllLikesByPost + * @param postid postid identifier + * return all the likes belonging to the postid + */ + List getAllLikesByFeed(String postid); + /** + * @param postid postid identifier + * return all the likes belonging to the postid + */ + List getAllLikesByPost(String postid); + /** + * + * @param hashtags the hashtag including the '#' + * @param postid the postid to which the hashtag is associated + * @param vreid VRE identifier + * @return true if success, false otherwise + * @throws FeedIDNotFoundException + */ + boolean saveHashTags(String postid, String vreid, List hashtags) throws FeedIDNotFoundException; + /** + * + * @param hashtags the hashtag including the '#' + * @param commentId the commentId to which the hashtag is associated + * @param vreid VRE identifier + * @return true if success, false otherwise + * @throws CommentIDNotFoundException + */ + boolean saveHashTagsComment(String commentId, String vreid, List hashtags) throws CommentIDNotFoundException; + /** + * + * @param hashtags the hashtag including the '#' + * @param postid the postid to which the hashtag is associated + * @param vreid VRE identifier + * @return true if success, false otherwise + * @throws FeedIDNotFoundException + */ + boolean deleteHashTags(String postid, String vreid, List hashtags) throws FeedIDNotFoundException; + /** + * + * @param hashtags the hashtag including the '#' + * @param commentId the commentId to which the hashtag is associated + * @param vreid VRE identifier + * @return true if success, false otherwise + * @throws CommentIDNotFoundException + */ + boolean deleteHashTagsComment(String commentId, String vreid, List hashtags) throws CommentIDNotFoundException; + /** + * get a map of vre hashtags where the key is the hashtag and the value is the occurrence of the hashtag in the VRE + * @param vreid vre identifier (scope) + * @return a HashMap of vre Hashtags associated with their occurrence + */ + Map getVREHashtagsWithOccurrence(String vreid); + /** + * get a map of vre hashtags where the key is the hashtag and the value is the occurrence of the hashtag in the VRE + * @param vreid vre identifier (scope) + * @param timestamp do not consider hashtags used before timestamp + * @return a HashMap of vre Hashtags associated with their occurrence + */ + Map getVREHashtagsWithOccurrenceFilteredByTime(String vreid, long timestamp); + /** + * @deprecated use getVREPostsByHashtag + * @param vreid VRE identifier + * @param hashtag the hashtag to look for including the '#', it is case sensitive + * @throws ColumnNameNotFoundException . + * @throws FeedIDNotFoundException . + * @throws FeedTypeNotFoundException . + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedIDNotFoundException . + * @return all the feeds having the hashtag passed as parameter + */ + List getVREFeedsByHashtag(String vreid, String hashtag) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * + * @param vreid VRE identifier + * @param hashtag the hashtag to look for including the '#', it is case sensitive + * @throws ColumnNameNotFoundException . + * @throws FeedIDNotFoundException . + * @throws FeedTypeNotFoundException . + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedIDNotFoundException . + * @return all the feeds having the hashtag passed as parameter + */ + List getVREPostsByHashtag(String vreid, String hashtag) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + + /** + * Save the invite for a given email into a given vre + * @param invite the invite object instanc to save + * @return {@link InviteOperationResult} SUCCESS, FAILED or ALREADY_INVITED (if an invite is sent to en existing email in the same environment more than once) + */ + InviteOperationResult saveInvite(Invite invite) throws AddressException; + /** + * + * @param vreid the environment where you want to check the invite + * @param email the email of the invite to check in the environmnet + * @return the InviteId if present, null otherwise + */ + String isExistingInvite(String vreid, String email); + /** + * read an invite from a given id + * @throws InviteIDNotFoundException + * @throws InviteStatusNotFoundException + */ + Invite readInvite(String inviteid) throws InviteIDNotFoundException, InviteStatusNotFoundException; + /** + * set the status of an invite, see {@link InviteStatus} + * @throws InviteIDNotFoundException + */ + boolean setInviteStatus(String vreid, String email, InviteStatus status) throws InviteIDNotFoundException, InviteStatusNotFoundException; + /** + * Use to get the list of invites per VRE + * @param vreid the vre id + * @param status optional, if you want to restict on the status, e.g. all pending invites + * @return return the list of invites + * @throws InviteIDNotFoundException + * @throws InviteStatusNotFoundException + */ + List getInvitedEmailsByVRE(String vreid, InviteStatus... status) throws InviteIDNotFoundException, InviteStatusNotFoundException; + /** + * + * @param feedId + * @return the list of attachments of the feed feedId, starting from the second one (first attachment is included in Feed instance already) + */ + List getAttachmentsByFeedId(String feedId) throws FeedIDNotFoundException; + + /** + * Retrieve all the ids of the vre + * @return the set of ids of the vre available or empty list in case of errors. + */ + public List getAllVREIds(); + + /** + * close the connection to the underlying database + */ + void closeConnection(); +} diff --git a/src/main/java/org/gcube/portal/databook/server/RunningCluster.java b/src/main/java/org/gcube/portal/databook/server/RunningCluster.java new file mode 100644 index 0000000..f137a9d --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/server/RunningCluster.java @@ -0,0 +1,220 @@ +package org.gcube.portal.databook.server; + +import static org.gcube.resources.discovery.icclient.ICFactory.clientFor; +import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.Serializable; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.gcube.common.portal.GCubePortalConstants; +import org.gcube.common.portal.PortalContext; +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; +import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.portal.databook.shared.ex.TooManyRunningClustersException; +import org.gcube.resources.discovery.client.api.DiscoveryClient; +import org.gcube.resources.discovery.client.queries.api.SimpleQuery; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * @author Massimiliano Assante ISTI-CNR + * @author Ahmed Salah Tawfik Ibrahim ISTI-CNR + * + * @version 2.0.0 October 2023 + * + */ +@SuppressWarnings("serial") +public class RunningCluster implements Serializable { + /** + * logger + */ + private static final Logger _log = LoggerFactory.getLogger(RunningCluster.class); + + /** + * properties to read + */ + private static final String HOST_PROPERTY = "host"; + private static final String HOST_PORT_PROPERTY = "port"; + private static final String DATACENTER_NAME_PROPERTY = "datacenter"; + private static final String KEY_SPACE_NAME_PROPERTY = "keyspace"; + /** + * other constants + */ + private final static String RUNTIME_RESOURCE_NAME = "SocialPortalDataStore"; + private final static String PLATFORM_NAME = "Cassandra"; + + private static final String DEFAULT_CONFIGURATION = "/org/gcube/portal/databook/server/resources/databook.properties"; + + private static RunningCluster singleton; + /** + * Host + */ + private String host; + /** + * Cluster Name + */ + private String datacenterName; + /** + * Keyspace Name + */ + private String keyspaceName; //to be modified + + /** + * @param infrastructureName could be null + * @return an instance of the RunningCluster + */ + public static synchronized RunningCluster getInstance(String infrastructureName) { + if (singleton == null) { + singleton = new RunningCluster(infrastructureName); + } + return singleton; + } + /** + * private constructor + */ + private RunningCluster(String infrastructureName) { + //Query the IS (for the future) + /*List resources = getConfigurationFromIS(infrastructureName); + if (resources.size() > 1) { + _log.error("Too many Runtime Resource having name " + RUNTIME_RESOURCE_NAME +" in this scope "); + throw new TooManyRunningClustersException("There exist more than 1 Runtime Resource in this scope having name " + + RUNTIME_RESOURCE_NAME + " and Platform " + PLATFORM_NAME + ". Only one allowed per infrasrtucture."); + } + else if (resources.size() == 0){ + _log.error("There is no Runtime Resource having name " + RUNTIME_RESOURCE_NAME +" and Platform " + PLATFORM_NAME + " in this scope. Using default configuration properties: " + DEFAULT_CONFIGURATION); + loadDefaultConfiguration(); + } + else { + for (ServiceEndpoint res : resources) { + AccessPoint found = res.profile().accessPoints().iterator().next(); + host = found.address(); + clusterName = found.description(); + keyspaceName = found.name(); + } + } + } catch (Exception e) { + e.printStackTrace(); + }*/ + + host = "10.1.28.55:9042, 10.1.30.142:9042, 10.1.28.100:9042"; + datacenterName = "1"; + keyspaceName = "dev_mig_new_schema_test"; + } + + /** + * + * @return the + * @throws Exception + */ + private List getConfigurationFromIS(String infrastructureName) throws Exception { + _log.debug("getConfigurationFromIS infrastructureName="+infrastructureName ); + String scope = "/"; + if(infrastructureName != null && !infrastructureName.isEmpty()) + scope += infrastructureName; + else { + scope += readInfrastructureName(); + _log.debug("infrastrucute name is null, setting root scope=" + scope); + } + String currScope = ScopeProvider.instance.get(); + ScopeProvider.instance.set(scope); + SimpleQuery query = queryFor(ServiceEndpoint.class); + query.addCondition("$resource/Profile/Name/text() eq '"+ RUNTIME_RESOURCE_NAME +"'"); + query.addCondition("$resource/Profile/Platform/Name/text() eq '"+ PLATFORM_NAME +"'"); + DiscoveryClient client = clientFor(ServiceEndpoint.class); + List toReturn = client.submit(query); + ScopeProvider.instance.set(currScope); + return toReturn; + } + + private String readInfrastructureName() { + + Properties props = new Properties(); + try { + StringBuilder sb = new StringBuilder(getCatalinaHome()); + sb.append(File.separator) + .append(PortalContext.CONFIGURATION_FOLDER) + .append(File.separator) + .append(PortalContext.INFRA_PROPERTY_FILENAME); + String propertyfile = sb.toString(); + File propsFile = new File(propertyfile); + FileInputStream fis = new FileInputStream(propsFile); + props.load( fis); + return props.getProperty(GCubePortalConstants.INFRASTRUCTURE_NAME); + } + catch(IOException e) { + _log.error("infrastructure.properties file not found under $CATALINA_HOME/conf/ dir, setting default infrastructure Name " + "gcube"); + return "gcube"; + } + } + + + /** + * + */ + private void loadDefaultConfiguration() { + Properties props = new Properties(); + try { + props.load(CassandraClusterConnection.class.getResourceAsStream(DEFAULT_CONFIGURATION)); + host = props.getProperty(HOST_PROPERTY) + ":" + props.getProperty(HOST_PORT_PROPERTY); + datacenterName = props.getProperty(DATACENTER_NAME_PROPERTY); + keyspaceName = props.getProperty(KEY_SPACE_NAME_PROPERTY); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + + public String getKeyspaceName() { + return keyspaceName; + } + + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + @Override + public String toString() { + return "RunningCluster [host=" + host + ", datacenterName=" + datacenterName + + ", keyspaceName=" + keyspaceName + "]"; + } + /** + * + * @return $CATALINA_HOME + */ + private static String getCatalinaHome() { + return (System.getenv("CATALINA_HOME").endsWith("/") ? System.getenv("CATALINA_HOME") : System.getenv("CATALINA_HOME")+"/"); + } + public void setDatacenterName(String datacenterName){ + this.datacenterName = datacenterName; + } + + public String getDatacenterName() { + return datacenterName; + } + + public List getHosts() { + List hosts = new ArrayList<>(); + String [] ips = host.split(", "); + for (String ip: ips){ + String[] ip_port = ip.split(":"); + hosts.add(new InetSocketAddress(ip_port[0], Integer.parseInt(ip_port[1]))); + } + return hosts; + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/server/Schema.java b/src/main/java/org/gcube/portal/databook/server/Schema.java new file mode 100644 index 0000000..522093e --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/server/Schema.java @@ -0,0 +1,68 @@ +package org.gcube.portal.databook.server; + +public class Schema { + //Tables + public static final String NOTIFICATIONS = "Notifications"; + public static final String POSTS = "Posts"; + public static final String COMMENTS = "Comments"; + public static final String LIKES = "Likes"; + public static final String INVITES = "Invites"; + public static final String VRE_TIMELINE_POSTS = "VRETimeline"; + public static final String USER_TIMELINE_POSTS = "UserTimeline"; + public static final String APP_TIMELINE_POSTS = "AppTimeline"; + public static final String USER_LIKED_POSTS = "UserLikes"; + public static final String USER_NOTIFICATIONS = "UserNotifications"; // regular user notifications timeline (both read and unread, messages are included) + public static final String USER_NOTIFICATIONS_UNREAD = "UserUnreadNotifications"; // only unread user notifications/ notifications messages + public static final String USER_NOTIFICATIONS_PREFERENCES = "UserNotificationsPreferences"; // preferences for notifications + public static final String HASHTAGS_COUNTER = "HashtagsCounter"; // count the hashtags per group and type + public static final String HASHTAGGED_POSTS = "HashtaggedPosts"; // contains hashtags per type associated with vre and POST + public static final String HASHTAGGED_COMMENTS = "HashtaggedComments"; // contains hashtags per type associated with vre and comment + public static final String VRE_INVITES = "VREInvites"; //contains the emails that were invited per VRE + public static final String EMAIL_INVITES = "EmailInvites"; //contains the list of invitation per email + public static final String ATTACHMENTS = "Attachments"; //contains the list of all the attachments in a POST + + //columns + public static final String USER_ID = "userid"; //text + public static final String TYPE = "type"; //text + public static final String PREFERENCE = "preference"; //text + public static final String TIMESTAMP = "timestamp"; //timestamp + public static final String NOT_ID = "notid"; //UUID + public static final String VRE_ID = "vreid"; //text + public static final String POST_ID = "postid"; //UUID + public static final String APP_ID = "appid"; //text + public static final String HASHTAG = "hashtag"; //text + public static final String COMMENT_ID = "commentid"; //UUID + public static final String COUNT = "count"; //big int + public static final String LIKE_ID = "likeid"; //UUID + public static final String INVITE_ID = "inviteid"; //UUID + public static final String STATUS = "status"; //text + public static final String EMAIL = "email"; //text + public static final String ATTACH_ID = "attachid"; //UUID + public static final String URI = "uri"; //text + public static final String NAME = "name"; //text + public static final String DESCRIPTION = "description"; //text + public static final String URI_THUMBNAIL = "urithumbnail"; //text + public static final String MIME_TYPE = "mimetype"; //text + public static final String SENDER_USER_ID = "senderuserid"; //text + public static final String CONTROL_CODE = "controlcode"; //text + public static final String SENDER_FULL_NAME = "senderfullname"; //text + public static final String FULL_NAME = "fullname"; //text + public static final String THUMBNAIL_URL = "thumbnailurl"; //text + public static final String COMMENT = "comment"; //text + public static final String IS_EDIT = "isedit"; //bool + public static final String LAST_EDIT_TIME = "lastedittime"; //timestamp + public static final String SUBJECT_ID = "subjectid"; //text + public static final String SENDER_ID = "senderid"; //text + public static final String SENDER_THUMBNAIL_URL = "senderthumbnailurl"; //text + public static final String IS_READ = "isread"; //bool + public static final String LINK_HOST = "linkhost"; //text + public static final String LIKES_NO = "likesno"; //big int + public static final String LINK_DESCRIPTION = "linkdescription"; //text + public static final String IS_APPLICATION_POST = "isapplicationpost"; //bool --> + public static final String ENTITY_ID = "entityid"; //text + public static final String PRIVACY = "privacy"; //text + public static final String MULTI_FILE_UPLOAD = "multifileupload"; //bool + public static final String COMMENTS_NO = "commentsno"; //big int + public static final String LINK_TITLE = "linktitle"; //text + +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/server/Tester.java b/src/main/java/org/gcube/portal/databook/server/Tester.java new file mode 100644 index 0000000..522de5b --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/server/Tester.java @@ -0,0 +1,45 @@ +package org.gcube.portal.databook.server; + +import org.gcube.portal.databook.shared.*; +import org.gcube.portal.databook.shared.ex.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class Tester { + private static DBCassandraAstyanaxImpl store; + private static Logger LOGGER = LoggerFactory.getLogger(Tester.class); + + public Tester() { + store = new DBCassandraAstyanaxImpl("gcube"); //set to true if you want to drop the KeySpace and recreate it + } + + public static void main(String[] args) throws ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException, FeedIDNotFoundException, FeedTypeNotFoundException { + Tester test = new Tester(); + //test.getComment(); + test.testFunc(); + System.exit(0); + + } + public void testFunc() throws ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException, FeedIDNotFoundException, FeedTypeNotFoundException { + String postIdToUpdate = "047c601d-2291-4974-9224-d6732b1fbe26"; + Post read = store.readPost(postIdToUpdate); + + List readC = store.getAllCommentByPost("047c601d-2291-4974-9224-d6732b1fbe26"); + System.out.println(read); + readC.forEach(c -> System.out.println(c.getText())); + } + public void getComment(){ + String uuid = "820969b2-4632-4197-9fd6-5aafab781faa"; + + Comment c; + try { + c = store.readCommentById(uuid); + System.out.println(c); + } catch (CommentIDNotFoundException e) { + // TODO Auto-generated catch block + System.err.println(e.toString()); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/server/resources/databook.properties b/src/main/java/org/gcube/portal/databook/server/resources/databook.properties new file mode 100644 index 0000000..c0fad71 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/server/resources/databook.properties @@ -0,0 +1,4 @@ +host = node1.d.cassandra.research-infrastructures.eu +port = 9160 +cluster = D4Science Cluster +keyspace = DevKeySpace \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/shared/ApplicationProfile.java b/src/main/java/org/gcube/portal/databook/shared/ApplicationProfile.java new file mode 100644 index 0000000..ef7593c --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ApplicationProfile.java @@ -0,0 +1,77 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; + +/** + * + * @author Massimiliano Assante, ISTI-CNR + * @version 0.1 Dec 2012 + * + */ +@SuppressWarnings("serial") +public class ApplicationProfile implements Serializable { + + private String key; + private String name; + private String description; + private String imageUrl; + private String scope; + private String url; + + public ApplicationProfile() { + super(); + } + + public ApplicationProfile(String key, String name, String description, String imageUrl, String scope, String url) { + super(); + this.key = key; + this.name = name; + this.description = description; + this.imageUrl = imageUrl; + this.scope = scope; + this.url = url; + } + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getImageUrl() { + return imageUrl; + } + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + public String getScope() { + return scope; + } + public void setScope(String scope) { + this.scope = scope; + } + + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + @Override + public String toString() { + return "ApplicationProfile [key=" + key + ", name=" + name + ", description=" + + description + ", imageUrl=" + imageUrl + ", scope=" + scope + + ", url=" + url + "]"; + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/Attachment.java b/src/main/java/org/gcube/portal/databook/shared/Attachment.java new file mode 100644 index 0000000..5b8e337 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/Attachment.java @@ -0,0 +1,104 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; + +import org.jsonmaker.gwt.client.Jsonizer; + +@SuppressWarnings("serial") +public class Attachment implements Serializable { + + public interface AttachmentJsonizer extends Jsonizer {} + + private String id; + private String uri; + private String name; + private String description; + private String thumbnailURL; + private String mimeType; + + public Attachment() { + super(); + } + + /** + * @param id the id in the cassandra CF + * @param uri where you can download the file from + * @param name the name of the attached file + * @param description the description of the attached file + * @param thumbnailURL the URL of the image representing the attached file + * @param mimeType the type of file + */ + public Attachment(String id, String uri, String name, String description, + String thumbnailURL, String mimeType) { + super(); + this.id = id; + this.uri = uri; + this.name = name; + this.description = description; + this.thumbnailURL = thumbnailURL; + this.mimeType = mimeType; + } + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + + public String getName() { + return name; + } + + + public void setName(String name) { + this.name = name; + } + + + public String getDescription() { + return description; + } + + + public void setDescription(String description) { + this.description = description; + } + + + public String getThumbnailURL() { + return thumbnailURL; + } + + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + @Override + public String toString() { + return "Attachment [uri=" + uri + ", name=" + name + ", description=" + + description + ", thumbnailURL=" + thumbnailURL + + ", mimeType=" + mimeType + "]"; + } + + + + +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ClientAttachment.java b/src/main/java/org/gcube/portal/databook/shared/ClientAttachment.java new file mode 100644 index 0000000..13acb08 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ClientAttachment.java @@ -0,0 +1,34 @@ +package org.gcube.portal.databook.shared; + +import jsinterop.annotations.JsOverlay; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object") +public class ClientAttachment { + public String id; + public String uri; + public String name; + public String description; + public String thumbnailURL; + public String mimeType; + /** + * @param id the id in the cassandra CF + * @param uri where you can download the file from + * @param name the name of the attached file + * @param description the description of the attached file + * @param thumbnailURL the URL of the image representing the attached file + * @param mimeType the type of file + */ + @JsOverlay + public static ClientAttachment create(String id, String uri, String name, String description, String thumbnailURL, String mimeType) { + ClientAttachment o = new ClientAttachment(); + o.id = id; + o.uri = uri; + o.name = name; + o.description = description; + o.thumbnailURL = thumbnailURL; + o.mimeType = mimeType; + return o; + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ClientFeed.java b/src/main/java/org/gcube/portal/databook/shared/ClientFeed.java new file mode 100644 index 0000000..07fe349 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ClientFeed.java @@ -0,0 +1,183 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import org.jsonmaker.gwt.client.Jsonizer; + + +/** + * + * @author Massimiliano Assante, ISTI-CNR + * + */ +@SuppressWarnings("serial") +public class ClientFeed implements Serializable { + + public interface ClientFeedJsonizer extends Jsonizer {} + + private String key; + private String type; + private String userid; + private Date time; + private String uri; + private String description; + private String fullName; + private String email; + private String thumbnailURL; + private String linkTitle; + private String linkDescription; + private String linkUrlThumbnail; + private String linkHost; + private List attachments; + + public ClientFeed() { + super(); + } + + public ClientFeed(String key, String type, String userid, Date time, + String uri, String description, String fullName, String email, + String thumbnailURL, String linkTitle, String linkDescription, + String linkUrlThumbnail, String linkHost, List attachments) { + super(); + this.key = key; + this.type = type; + this.userid = userid; + this.time = time; + this.uri = uri; + this.description = description; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.linkTitle = linkTitle; + this.linkDescription = linkDescription; + this.linkUrlThumbnail = linkUrlThumbnail; + this.linkHost = linkHost; + this.attachments = attachments; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUserid() { + return userid; + } + + public void setUserid(String userid) { + this.userid = userid; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String getLinkTitle() { + return linkTitle; + } + + public void setLinkTitle(String linkTitle) { + this.linkTitle = linkTitle; + } + + public String getLinkDescription() { + return linkDescription; + } + + public void setLinkDescription(String linkDescription) { + this.linkDescription = linkDescription; + } + + public String getLinkUrlThumbnail() { + return linkUrlThumbnail; + } + + public void setLinkUrlThumbnail(String linkUrlThumbnail) { + this.linkUrlThumbnail = linkUrlThumbnail; + } + + public String getLinkHost() { + return linkHost; + } + + public void setLinkHost(String linkHost) { + this.linkHost = linkHost; + } + + + public List getAttachments() { + return attachments; + } + + public void setAttachments(List attachments) { + this.attachments = attachments; + } + + @Override + public String toString() { + return "ClientFeed [key=" + key + ", type=" + type + ", userid=" + + userid + ", time=" + time + ", uri=" + uri + ", description=" + + description + ", fullName=" + fullName + ", email=" + email + + ", thumbnailURL=" + thumbnailURL + ", linkTitle=" + linkTitle + + ", linkDescription=" + linkDescription + + ", linkUrlThumbnail=" + linkUrlThumbnail + ", linkHost=" + + linkHost + ", attachments=" + attachments + "]"; + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ClientPost.java b/src/main/java/org/gcube/portal/databook/shared/ClientPost.java new file mode 100644 index 0000000..2fab59b --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ClientPost.java @@ -0,0 +1,51 @@ +package org.gcube.portal.databook.shared; + +import java.util.Date; + +import jsinterop.annotations.JsOverlay; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; +/** + * + * @author Massimiliano Assante, CNR-ISTI + * Uses JsInterop annotations to deserialize the object + */ +@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object") +public class ClientPost { + public String key; + public String type; + public String userid; + public Date time; + public String uri; + public String description; + public String fullName; + public String email; + public String thumbnailURL; + public String linkTitle; + public String linkDescription; + public String linkUrlThumbnail; + public String linkHost; + public ClientAttachment[] attachments; + @JsOverlay + public static ClientPost create(String key, String type, String userid, Date time, + String uri, String description, String fullName, String email, + String thumbnailURL, String linkTitle, String linkDescription, + String linkUrlThumbnail, String linkHost, ClientAttachment[] attachments) { + ClientPost o = new ClientPost(); + o.key = key; + o.type = type; + o.userid = userid; + o.time = time; + o.uri = uri; + o.description = description; + o.fullName = fullName; + o.email = email; + o.thumbnailURL = thumbnailURL; + o.linkTitle = linkTitle; + o.linkDescription = linkDescription; + o.linkUrlThumbnail = linkUrlThumbnail; + o.linkHost = linkHost; + o.attachments = attachments; + return o; + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/Comment.java b/src/main/java/org/gcube/portal/databook/shared/Comment.java new file mode 100644 index 0000000..f8042e8 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/Comment.java @@ -0,0 +1,175 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.Date; + +/** + * + * @author Massimiliano Assante, ISTI-CNR + * @version 0.1 July 2012 + * + */ +@SuppressWarnings("serial") +public class Comment implements Serializable, Comparable { + + private String key; + private String userid; + private Date time; + private String feedid; + private String text; + private String fullName; + private String thumbnailURL; + private boolean isEdit; // false default + private Date lastEditTime; // null default + + /** + * + */ + public Comment() { + super(); + } + /** + * + * @param key + * @param userid + * @param time + * @param feedid + * @param text + * @param fullName + * @param thumbnailURL + */ + public Comment(String key, String userid, Date time, String feedid, + String text, String fullName, String thumbnailURL) { + super(); + this.key = key; + this.userid = userid; + this.time = time; + this.feedid = feedid; + this.text = text; + this.fullName = fullName; + this.thumbnailURL = thumbnailURL; + this.isEdit = false; + this.lastEditTime = null; + + } + + /** + * Constructor for edited comment + * @param key + * @param userid + * @param time + * @param feedid + * @param text + * @param fullName + * @param thumbnailURL + * @param isEdit + * @param editDate + */ + public Comment(String key, String userid, Date time, String feedid, + String text, String fullName, String thumbnailURL, boolean isEdit, Date editDate) { + super(); + this.key = key; + this.userid = userid; + this.time = time; + this.feedid = feedid; + this.text = text; + this.fullName = fullName; + this.thumbnailURL = thumbnailURL; + this.isEdit = isEdit; + this.lastEditTime = editDate; + } + + /** + * + * @return the text + */ + public String getText() { + return text; + } + /** + * + * @param text text to add as string + */ + public void setText(String text) { + this.text = text; + } + /** + * + * @return the uuid + */ + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getUserid() { + return userid; + } + + public void setUserid(String userid) { + this.userid = userid; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getFeedid() { + return feedid; + } + + public void setFeedid(String feedid) { + this.feedid = feedid; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public boolean isEdit() { + return isEdit; + } + public void setEdit(boolean isEdit) { + this.isEdit = isEdit; + } + public Date getLastEditTime() { + return lastEditTime; + } + public void setLastEditTime(Date lastEditTime) { + this.lastEditTime = lastEditTime; + } + public int compareTo(Comment toCompare) { + if (this.time.after(toCompare.getTime())) + return 1; + if (this.time.before(toCompare.getTime())) + return -1; + return 0; + } + + @Override + public String toString() { + return "Comment [key=" + key + ", userid=" + userid + ", time=" + time + + ", feedid=" + feedid + ", text=" + text + ", fullName=" + + fullName + ", thumbnailURL=" + thumbnailURL + ", isEdit=" + + isEdit + ", lastEditTime=" + lastEditTime + "]"; + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/EnhancedFeed.java b/src/main/java/org/gcube/portal/databook/shared/EnhancedFeed.java new file mode 100644 index 0000000..f258516 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/EnhancedFeed.java @@ -0,0 +1,85 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.ArrayList; +/** + * + * @author massi + * This class contains addtional user related information about a Feed + * e.g. if this user has liked it + */ +@SuppressWarnings("serial") +public class EnhancedFeed implements Serializable{ + private Feed feed; + private boolean liked; + private boolean isUsers; + private ArrayList comments; + private ArrayList attachments; + + + public EnhancedFeed() { + super(); + } + public EnhancedFeed(Feed feed, boolean liked, boolean isUsers) { + super(); + this.feed = feed; + this.liked = liked; + this.isUsers = isUsers; + } + + public EnhancedFeed(Feed feed, boolean liked, boolean isUsers, ArrayList comments) { + super(); + this.isUsers = isUsers; + this.feed = feed; + this.liked = liked; + this.comments = comments; + } + + + public EnhancedFeed(Feed feed, boolean liked, boolean isUsers, + ArrayList comments, ArrayList attachments) { + super(); + this.feed = feed; + this.liked = liked; + this.isUsers = isUsers; + this.comments = comments; + this.attachments = attachments; + } + public ArrayList getComments() { + return comments; + } + public void setComments(ArrayList comments) { + this.comments = comments; + } + public Feed getFeed() { + return feed; + } + public void setFeed(Feed feed) { + this.feed = feed; + } + public boolean isLiked() { + return liked; + } + public void setLiked(boolean liked) { + this.liked = liked; + } + public boolean isUsers() { + return isUsers; + } + public void setUsers(boolean isUsers) { + this.isUsers = isUsers; + } + public ArrayList getAttachments() { + return attachments; + } + public void setAttachments(ArrayList attachments) { + this.attachments = attachments; + } + @Override + public String toString() { + return "EnhancedFeed [feed=" + feed + ", liked=" + liked + ", isUsers=" + + isUsers + ", comments=" + comments + ", attachments=" + + attachments + "]"; + } + +} diff --git a/src/main/java/org/gcube/portal/databook/shared/Feed.java b/src/main/java/org/gcube/portal/databook/shared/Feed.java new file mode 100644 index 0000000..514a0db --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/Feed.java @@ -0,0 +1,322 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.Date; + +/** + * + * @author Massimiliano Assante, ISTI-CNR + * @deprecated use org.gcube.portal.databook.shared.Post instead + */ +@SuppressWarnings("serial") +public class Feed implements Serializable, Comparable { + + private String key; + private FeedType type; + private String entityId; + private Date time; + private String vreid; + private String uri; + private String uriThumbnail; + private String description; + private PrivacyLevel privacy; + private String fullName; + private String email; + private String thumbnailURL; + private String commentsNo; + private String likesNo; + private String linkTitle; + private String linkDescription; + private String linkHost; + boolean applicationFeed; + /** + * this boolean indicates that the attachments to the post are > 1 + */ + boolean multiFileUpload; + /** + * default constructor + */ + public Feed() { + super(); + } + /** + * To use ONLY for USER Feeds + * + * + * @param key a UUID + * @param type an instance of FeedType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + * @param linkHost option to be used when posting linkgs + */ + public Feed(String key, FeedType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String linkTitle, String linkDescription, String linkHost) { + this.key = key; + this.type = type; + this.entityId = entityId; + this.time = time; + this.vreid = vreid; + this.uri = uri; + this.uriThumbnail = uriThumbnail; + this.description = description; + this.privacy = privacy; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.commentsNo = "0"; + this.likesNo = "0"; + this.linkDescription = linkDescription; + this.linkTitle = linkTitle; + this.linkHost = linkHost; + this.applicationFeed = false; + } + /** + * To use for USER and ApplicationProfile Feeds + * + * @param key a UUID + * @param type an instance of FeedType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + * @param applicationFeed tell if this is an application feed or a user feed + */ + public Feed(String key, FeedType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String linkTitle, String linkDescription, String linkHost, boolean applicationFeed) { + this(key, type, entityId, time, vreid, uri, uriThumbnail, description, privacy, fullName, email, thumbnailURL, linkTitle, linkDescription, linkHost); + this.applicationFeed = applicationFeed; + } + + + /** + * for serialization purposes + * @param key a UUID + * @param type an instance of FeedType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + */ + public Feed(String key, FeedType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String commentsNo, + String likesNo, String linkTitle, String linkDescription, String linkHost, boolean applicationFeed, boolean multiFileUpload) { + super(); + this.key = key; + this.type = type; + this.entityId = entityId; + this.time = time; + this.vreid = vreid; + this.uri = uri; + this.uriThumbnail = uriThumbnail; + this.description = description; + this.privacy = privacy; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.commentsNo = commentsNo; + this.likesNo = likesNo; + this.linkDescription = linkDescription; + this.linkTitle = linkTitle; + this.linkHost = linkHost; + this.applicationFeed = applicationFeed; + this.multiFileUpload = multiFileUpload; + } + /** + * + * @return the key + */ + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public FeedType getType() { + return type; + } + + public void setType(FeedType type) { + this.type = type; + } + /** + * + * @return the User or the App id + */ + public String getEntityId() { + return entityId; + } + /** + * set the User or the App id + * @param entityId the UserId or the AppId id + */ + public void setEntityId(String entityId) { + this.entityId = entityId; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getVreid() { + return vreid; + } + + public void setVreid(String vreid) { + this.vreid = vreid; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public PrivacyLevel getPrivacy() { + return privacy; + } + + public void setPrivacy(PrivacyLevel privacy) { + this.privacy = privacy; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String getCommentsNo() { + return commentsNo; + } + public void setCommentsNo(String commentsNo) { + this.commentsNo = commentsNo; + } + public String getLikesNo() { + return likesNo; + } + public void setLikesNo(String likesNo) { + this.likesNo = likesNo; + } + public String getUriThumbnail() { + return uriThumbnail; + } + public void setUriThumbnail(String uriThumbnail) { + this.uriThumbnail = uriThumbnail; + } + + public String getLinkTitle() { + return linkTitle; + } + public void setLinkTitle(String linkTitle) { + this.linkTitle = linkTitle; + } + public String getLinkDescription() { + return linkDescription; + } + public void setLinkDescription(String linkDescription) { + this.linkDescription = linkDescription; + } + public int compareTo(Feed toCompare) { + if (this.time.after(toCompare.getTime())) + return 1; + if (this.time.before(toCompare.getTime())) + return -1; + return 0; + } + public String getLinkHost() { + return linkHost; + } + public void setLinkHost(String linkHost) { + this.linkHost = linkHost; + } + + public boolean isApplicationFeed() { + return applicationFeed; + } + public void setApplicationFeed(boolean applicationFeed) { + this.applicationFeed = applicationFeed; + } + public boolean isMultiFileUpload() { + return multiFileUpload; + } + public void setMultiFileUpload(boolean multiFileUpload) { + this.multiFileUpload = multiFileUpload; + } + @Override + public String toString() { + return "Feed [key=" + key + ", type=" + type + ", entityId=" + entityId + + ", time=" + time + ", vreid=" + vreid + ", uri=" + uri + + ", uriThumbnail=" + uriThumbnail + ", description=" + + description + ", privacy=" + privacy + ", fullName=" + + fullName + ", email=" + email + ", thumbnailURL=" + + thumbnailURL + ", commentsNo=" + commentsNo + ", likesNo=" + + likesNo + ", linkTitle=" + linkTitle + ", linkDescription=" + + linkDescription + ", linkHost=" + linkHost + + ", applicationFeed=" + applicationFeed + + ", multiFileUpload=" + multiFileUpload + "]"; + } + +} diff --git a/src/main/java/org/gcube/portal/databook/shared/FeedType.java b/src/main/java/org/gcube/portal/databook/shared/FeedType.java new file mode 100644 index 0000000..71fe688 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/FeedType.java @@ -0,0 +1,19 @@ +package org.gcube.portal.databook.shared; + +/** + * @author Massimiliano Assante ISTI-CNR + * @deprecated use PostType + * @version 1.2 October 2012 + */ +public enum FeedType { + JOIN, SHARE, PUBLISH, TWEET, CONNECTED, + /** + * Special case used when accounting + */ + ACCOUNTING, + /** + * Special case used when a Feed is removed + */ + DISABLED; +} + diff --git a/src/main/java/org/gcube/portal/databook/shared/ImageType.java b/src/main/java/org/gcube/portal/databook/shared/ImageType.java new file mode 100644 index 0000000..15f2719 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ImageType.java @@ -0,0 +1,5 @@ +package org.gcube.portal.databook.shared; + +public enum ImageType { + JPG, GIF, PNG, TIFF, PDF, BMP; +} diff --git a/src/main/java/org/gcube/portal/databook/shared/Invite.java b/src/main/java/org/gcube/portal/databook/shared/Invite.java new file mode 100644 index 0000000..be1548d --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/Invite.java @@ -0,0 +1,144 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.Date; +/** + * + * @author Massimiliano Assante, ISTI-CNR + * + */ +@SuppressWarnings("serial") +public class Invite implements Serializable { + + private String key; + private String senderUserId; + private String vreid; + private String invitedEmail; + private String controlCode; + private InviteStatus status; + private Date time; + private String senderFullName; + + + public Invite() { + super(); + } + + + + + public Invite(String key, String senderUserId, String vreid, + String invitedEmail, String controlCode, InviteStatus status, + Date time, String senderFullName) { + super(); + this.key = key; + this.senderUserId = senderUserId; + this.vreid = vreid; + this.invitedEmail = invitedEmail; + this.controlCode = controlCode; + this.status = status; + this.time = time; + this.senderFullName = senderFullName; + } + + + + + public String getKey() { + return key; + } + + + + + public void setKey(String key) { + this.key = key; + } + + + + + public String getSenderUserId() { + return senderUserId; + } + + + public void setSenderUserId(String senderUserId) { + this.senderUserId = senderUserId; + } + + + public String getVreid() { + return vreid; + } + + + public void setVreid(String vreid) { + this.vreid = vreid; + } + + + public String getInvitedEmail() { + return invitedEmail; + } + + + public void setInvitedEmail(String invitedEmail) { + this.invitedEmail = invitedEmail; + } + + + public String getControlCode() { + return controlCode; + } + + + public void setControlCode(String controlCode) { + this.controlCode = controlCode; + } + + + public InviteStatus getStatus() { + return status; + } + + + public void setStatus(InviteStatus status) { + this.status = status; + } + + + public Date getTime() { + return time; + } + + + public void setTime(Date time) { + this.time = time; + } + + + public String getSenderFullName() { + return senderFullName; + } + + + public void setSenderFullName(String senderFullName) { + this.senderFullName = senderFullName; + } + + + + + @Override + public String toString() { + return "Invite [key=" + key + ", senderUserId=" + senderUserId + + ", vreid=" + vreid + ", invitedEmail=" + invitedEmail + + ", controlCode=" + controlCode + ", status=" + status + + ", time=" + time + ", senderFullName=" + senderFullName + "]"; + } + + + + +} diff --git a/src/main/java/org/gcube/portal/databook/shared/InviteOperationResult.java b/src/main/java/org/gcube/portal/databook/shared/InviteOperationResult.java new file mode 100644 index 0000000..da0327f --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/InviteOperationResult.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared; + +public enum InviteOperationResult { + SUCCESS, + FAILED, + //If I send an invite the same email in the same environment more than once + ALREADY_INVITED; +} diff --git a/src/main/java/org/gcube/portal/databook/shared/InviteStatus.java b/src/main/java/org/gcube/portal/databook/shared/InviteStatus.java new file mode 100644 index 0000000..62df7ea --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/InviteStatus.java @@ -0,0 +1,20 @@ +package org.gcube.portal.databook.shared; + +public enum InviteStatus { + /** + * First status of anyh invite + */ + PENDING, + /** + * User accepted the invite + */ + ACCEPTED, + /** + * User rejected the invite + */ + REJECTED, + /** + * Manager withdrawed the invite + */ + RETRACTED; +} diff --git a/src/main/java/org/gcube/portal/databook/shared/JSON.java b/src/main/java/org/gcube/portal/databook/shared/JSON.java new file mode 100644 index 0000000..7a660f0 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/JSON.java @@ -0,0 +1,10 @@ +package org.gcube.portal.databook.shared; + +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class JSON { + public static native String stringify(Object o); + public static native O parse(String json); +} diff --git a/src/main/java/org/gcube/portal/databook/shared/JobStatusType.java b/src/main/java/org/gcube/portal/databook/shared/JobStatusType.java new file mode 100644 index 0000000..126aaea --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/JobStatusType.java @@ -0,0 +1,53 @@ +package org.gcube.portal.databook.shared; +/** + * + * @author Massimiliano Assante, ISTI-CNR + * @version 0.1 Dec 2012 + * + */ +public enum JobStatusType { + /** + * The job has been cancelled. + */ + CANCELLED, + /** + * The job is in the process of being cancelled. + */ + CANCELLING, + /** + * The job has been deleted. + */ + DELETED, + /** + * The job is in the process of being deleted. + */ + DELETING,// + /** + * The job is being executed by job processor. + */ + EXECUTING,// + /** + * he job execution has failed. + */ + FAILED, + /** + * The job is new. + */ + NEW,// + /** + * The job is submitted for execution. + */ + SUBMITTED, + /** + * The job has completed successfully + */ + SUCCEEDED, + /** + * The job execution has timed out. + */ + TIMED_OUT, + /** + * The job is waiting for available job processor. + */ + WAITING +} diff --git a/src/main/java/org/gcube/portal/databook/shared/Like.java b/src/main/java/org/gcube/portal/databook/shared/Like.java new file mode 100644 index 0000000..d772865 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/Like.java @@ -0,0 +1,88 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.Date; +/** + * + * @author Massimiliano Assante, ISTI-CNR + * @version 0.1 July 2012 + * + */ +@SuppressWarnings("serial") +public class Like implements Serializable { + + private String key; + private String userid; + private Date time; + private String feedid; + private String fullName; + private String thumbnailURL; + + public Like() { + super(); + } + + public Like(String key, String userid, Date time, String feedid, + String fullName, String thumbnailURL) { + super(); + this.key = key; + this.userid = userid; + this.time = time; + this.feedid = feedid; + this.fullName = fullName; + this.thumbnailURL = thumbnailURL; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getUserid() { + return userid; + } + + public void setUserid(String userid) { + this.userid = userid; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getFeedid() { + return feedid; + } + + public void setFeedid(String feedid) { + this.feedid = feedid; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String toString() { + return "KEY: " + key + " Time: "+ time + "\nuserid: "+userid + " Full name: " + fullName; + + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/Notification.java b/src/main/java/org/gcube/portal/databook/shared/Notification.java new file mode 100644 index 0000000..36ee57d --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/Notification.java @@ -0,0 +1,193 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.Date; + +/** + * + * @author Massimiliano Assante, ISTI-CNR + * + */ +@SuppressWarnings("serial") +public class Notification implements Serializable { + + private String key; + private NotificationType type; + private String userid; + private String subjectid; + private Date time; + private String uri; + private String description; + private boolean read; + private String senderid; + private String senderFullName; + private String senderThumbnail; + private String commentKey; + + + /** + * default constructor + */ + public Notification() { + super(); + } + + + + /** + * + * @param key + * @param type + * @param userid + * @param subjectid the subject id of this notification, if is a like on a feed then is the feedid, it is a message then is the messageid and so on + * @param time + * @param uri + * @param description + * @param read + * @param senderid + * @param senderFullName + * @param senderThumbnail + */ + public Notification(String key, NotificationType type, String userid, + String subjectid, Date time, String uri, String description, + boolean read, String senderid, String senderFullName, + String senderThumbnail) { + super(); + this.key = key; + this.type = type; + this.userid = userid; + this.subjectid = subjectid; + this.time = time; + this.uri = uri; + this.description = description; + this.read = read; + this.senderid = senderid; + this.senderFullName = senderFullName; + this.senderThumbnail = senderThumbnail; + } + + /** + * + * @param key + * @param type + * @param userid + * @param subjectid the subject id of this notification, if is a like on a feed then is the feedid, it is a message then is the messageid and so on + * @param time + * @param uri + * @param description + * @param read + * @param senderid + * @param senderFullName + * @param senderThumbnail + * @param commentKey when a mail notification must be sent, stop the embedded discussion at this comment + */ + public Notification(String key, NotificationType type, String userid, + String subjectid, Date time, String uri, String description, + boolean read, String senderid, String senderFullName, + String senderThumbnail, String commentKey) { + super(); + this.key = key; + this.type = type; + this.userid = userid; + this.subjectid = subjectid; + this.time = time; + this.uri = uri; + this.description = description; + this.read = read; + this.senderid = senderid; + this.senderFullName = senderFullName; + this.senderThumbnail = senderThumbnail; + this.commentKey = commentKey; + } + + /** + * + * @return . + */ + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + public NotificationType getType() { + return type; + } + public void setType(NotificationType type) { + this.type = type; + } + public String getUserid() { + return userid; + } + public void setUserid(String userid) { + this.userid = userid; + } + public Date getTime() { + return time; + } + public void setTime(Date time) { + this.time = time; + } + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public boolean isRead() { + return read; + } + public void setRead(boolean read) { + this.read = read; + } + public String getSenderid() { + return senderid; + } + public void setSenderid(String senderid) { + this.senderid = senderid; + } + public String getSenderFullName() { + return senderFullName; + } + public void setSenderFullName(String senderFullName) { + this.senderFullName = senderFullName; + } + public String getSenderThumbnail() { + return senderThumbnail; + } + public void setSenderThumbnail(String senderThumbnail) { + this.senderThumbnail = senderThumbnail; + } + public String getSubjectid() { + return subjectid; + } + public void setSubjectid(String subjectid) { + this.subjectid = subjectid; + } + + public String getCommentKey() { + return commentKey; + } + + + + public void setCommentKey(String commentKey) { + this.commentKey = commentKey; + } + + @Override + public String toString() { + return "Notification [key=" + key + ", type=" + type + ", userid=" + + userid + ", subjectid=" + subjectid + ", time=" + time + + ", uri=" + uri + ", description=" + description + ", read=" + + read + ", senderid=" + senderid + ", senderFullName=" + + senderFullName + ", senderThumbnail=" + senderThumbnail + + ", commentKey=" + commentKey + "]"; + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/NotificationChannelType.java b/src/main/java/org/gcube/portal/databook/shared/NotificationChannelType.java new file mode 100644 index 0000000..d66a0ed --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/NotificationChannelType.java @@ -0,0 +1,20 @@ +package org.gcube.portal.databook.shared; +/** + * @author Massimiliano Assante ISTI-CNR + * + * @version 1.0 January 2012 + */ +public enum NotificationChannelType { + /** + * PORTAL + */ + PORTAL, + /** + * EMAIL + */ + EMAIL, + /** + * TWITTER + */ + TWITTER; +} diff --git a/src/main/java/org/gcube/portal/databook/shared/NotificationType.java b/src/main/java/org/gcube/portal/databook/shared/NotificationType.java new file mode 100644 index 0000000..36ddfa9 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/NotificationType.java @@ -0,0 +1,181 @@ +package org.gcube.portal.databook.shared; + + + +/** + * @author Massimiliano Assante ISTI-CNR + * + * TODO: Buggy if NotificationType for WP_* are refactored see DBCassandraAstyanaxImpl#getUserNotificationPreferences(String userid) + * introduced due to urgent matters + */ +public enum NotificationType { + /** + * use to notify a user he got a Tabular Resource shared + */ + TDM_TAB_RESOURCE_SHARE, + /** + * use to notify a user he got a TDM Rule shared + */ + TDM_RULE_SHARE, + /** + * use to notify a user he got a TDM Templated shared + */ + TDM_TEMPLATE_SHARE, + /** + * use to notify a user he got a workspace folder shared + */ + WP_FOLDER_SHARE, + /** + * use to notify a user that a user in the share unshared + */ + WP_FOLDER_UNSHARE, + /** + * use to notify a user that he got upgraded to administrator of a shared folder + */ + WP_ADMIN_UPGRADE, + /** + * use to notify a user that he got downgraded from administrator of a shared folder + */ + WP_ADMIN_DOWNGRADE, + /** + * use to notify a user that a new user was added in on of his workspace shared folder + */ + WP_FOLDER_ADDEDUSER, + /** + * use to notify a user that an existing user was removed from one of his workspace shared folder + */ + WP_FOLDER_REMOVEDUSER, + /** + * use to notify a user he got a workspace folder renamed + */ + WP_FOLDER_RENAMED, + /** + * use to notify a user he got a workspace item deleted from one of his workspace shared folder + */ + WP_ITEM_DELETE, + /** + * use to notify a user he got a workspace item updated from one of his workspace shared folder + */ + WP_ITEM_UPDATED, + /** + * use to notify a user he got a workspace item renamed from one of his workspace shared folder + */ + WP_ITEM_RENAMED, + /** + * use to notify a user he got a workspace item new in some of his workspace shared folder + */ + WP_ITEM_NEW, + /** + * use to notify a user he got one of his feed commented + */ + OWN_COMMENT, + /** + * use to notify a user that commented on a feed (Not his) that someone commented too + */ + COMMENT, + /** + * use to notify a user that he got mentioned in one post + */ + MENTION, + /** + * use to notify a user he got one of his feed liked + */ + LIKE, + /** + * use to notify a user he got a message + */ + MESSAGE, + /** + * use to notify every user of a VRE/Group that the post was made + */ + POST_ALERT, + /** + * use to notify a user that someone in his VRE created a new Event in the Calendar + */ + CALENDAR_ADDED_EVENT, + /** + * use to notify a user that someone in his VRE updated an Event in the Calendar + */ + CALENDAR_UPDATED_EVENT, + /** + * use to notify a user that someone in his VRE deleted an Event in the Calendar + */ + CALENDAR_DELETED_EVENT, + /** + * use to notify a user he got a connections request + */ + REQUEST_CONNECTION, + /** + * use to notify a user he got a job completed ok + */ + JOB_COMPLETED_OK, + /** + * use to notify a user he got a job completed not ok + */ + JOB_COMPLETED_NOK, + /** + * use to notify a document workflow owner that someone + * has edited a document involved in a worflow he created + */ + @Deprecated + DOCUMENT_WORKFLOW_EDIT, + /** + * use to notify a document workflow owner that someone + * has viewed a document involved in a worflow he created + */ + @Deprecated + DOCUMENT_WORKFLOW_VIEW, + /** + * use to notify a document workflow user (user that in the same document workflow) + * that forwarded to a step where he is requested to do a task + */ + @Deprecated + DOCUMENT_WORKFLOW_STEP_REQUEST_TASK, + /** + * use to notify a document workflow user that he was involved into a new Document Workflow + * and he is requested to do a task + */ + @Deprecated + DOCUMENT_WORKFLOW_FIRST_STEP_REQUEST_INVOLVMENT, + /** + * use to notify a document workflow owner that a user performed a forward action to another step a document worflow he created + */ + @Deprecated + DOCUMENT_WORKFLOW_USER_FORWARD_TO_OWNER, + /** + * use to notify a document workflow owner that someone + * forwarded and the workflow moved to another step a document worflow he created + */ + @Deprecated + DOCUMENT_WORKFLOW_FORWARD_STEP_COMPLETED_OWNER, + /** + * use to notify a document workflow peer (user that in the same step has your same role) + * that someone performed a forward action to another step in a document worflow he is involved into + */ + @Deprecated + DOCUMENT_WORKFLOW_STEP_FORWARD_PEER, + /** + * catalogue, use to notify someone submits an item for consideration + */ + CAT_ITEM_SUBMITTED, + /** + * catalogue, use to notify someone rejected a submitted item + */ + CAT_ITEM_REJECTED, + /** + * catalogue, use to notify someone published an item + */ + CAT_ITEM_PUBLISHED, + /** + * catalogue, use to notify someone updated an item + */ + CAT_ITEM_UPDATED, + /** + * catalogue, use to notify someone removed an item + */ + CAT_ITEM_DELETE, + /** + * generic notification + */ + GENERIC; +} diff --git a/src/main/java/org/gcube/portal/databook/shared/Post.java b/src/main/java/org/gcube/portal/databook/shared/Post.java new file mode 100644 index 0000000..517d1ff --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/Post.java @@ -0,0 +1,322 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.Date; + +/** + * + * @author Massimiliano Assante, ISTI-CNR + * + */ +@SuppressWarnings("serial") +public class Post implements Serializable, Comparable { + + private String key; + private PostType type; + private String entityId; + private Date time; + private String vreid; + private String uri; + private String uriThumbnail; + private String description; + private PrivacyLevel privacy; + private String fullName; + private String email; + private String thumbnailURL; + private String commentsNo; + private String likesNo; + private String linkTitle; + private String linkDescription; + private String linkHost; + boolean applicationFeed; + /** + * this boolean indicates that the attachments to the post are > 1 + */ + boolean multiFileUpload; + /** + * default constructor + */ + public Post() { + super(); + } + /** + * To use ONLY for USER Feeds + * + * + * @param key a UUID + * @param type an instance of PostType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + * @param linkHost option to be used when posting linkgs + */ + public Post(String key, PostType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String linkTitle, String linkDescription, String linkHost) { + this.key = key; + this.type = type; + this.entityId = entityId; + this.time = time; + this.vreid = vreid; + this.uri = uri; + this.uriThumbnail = uriThumbnail; + this.description = description; + this.privacy = privacy; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.commentsNo = "0"; + this.likesNo = "0"; + this.linkDescription = linkDescription; + this.linkTitle = linkTitle; + this.linkHost = linkHost; + this.applicationFeed = false; + } + /** + * To use for USER and ApplicationProfile Feeds + * + * @param key a UUID + * @param type an instance of FeedType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + * @param applicationFeed tell if this is an application feed or a user feed + */ + public Post(String key, PostType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String linkTitle, String linkDescription, String linkHost, boolean applicationFeed) { + this(key, type, entityId, time, vreid, uri, uriThumbnail, description, privacy, fullName, email, thumbnailURL, linkTitle, linkDescription, linkHost); + this.applicationFeed = applicationFeed; + } + + + /** + * for serialization purposes + * @param key a UUID + * @param type an instance of PostType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + */ + public Post(String key, PostType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String commentsNo, + String likesNo, String linkTitle, String linkDescription, String linkHost, boolean applicationFeed, boolean multiFileUpload) { + super(); + this.key = key; + this.type = type; + this.entityId = entityId; + this.time = time; + this.vreid = vreid; + this.uri = uri; + this.uriThumbnail = uriThumbnail; + this.description = description; + this.privacy = privacy; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.commentsNo = commentsNo; + this.likesNo = likesNo; + this.linkDescription = linkDescription; + this.linkTitle = linkTitle; + this.linkHost = linkHost; + this.applicationFeed = applicationFeed; + this.multiFileUpload = multiFileUpload; + } + /** + * + * @return post id + */ + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public PostType getType() { + return type; + } + + public void setType(PostType type) { + this.type = type; + } + /** + * + * @return the User or the App id + */ + public String getEntityId() { + return entityId; + } + /** + * set the User or the App id + * @param entityId the UserId or the AppId id + */ + public void setEntityId(String entityId) { + this.entityId = entityId; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getVreid() { + return vreid; + } + + public void setVreid(String vreid) { + this.vreid = vreid; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public PrivacyLevel getPrivacy() { + return privacy; + } + + public void setPrivacy(PrivacyLevel privacy) { + this.privacy = privacy; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String getCommentsNo() { + return commentsNo; + } + public void setCommentsNo(String commentsNo) { + this.commentsNo = commentsNo; + } + public String getLikesNo() { + return likesNo; + } + public void setLikesNo(String likesNo) { + this.likesNo = likesNo; + } + public String getUriThumbnail() { + return uriThumbnail; + } + public void setUriThumbnail(String uriThumbnail) { + this.uriThumbnail = uriThumbnail; + } + + public String getLinkTitle() { + return linkTitle; + } + public void setLinkTitle(String linkTitle) { + this.linkTitle = linkTitle; + } + public String getLinkDescription() { + return linkDescription; + } + public void setLinkDescription(String linkDescription) { + this.linkDescription = linkDescription; + } + public int compareTo(Post toCompare) { + if (this.time.after(toCompare.getTime())) + return 1; + if (this.time.before(toCompare.getTime())) + return -1; + return 0; + } + public String getLinkHost() { + return linkHost; + } + public void setLinkHost(String linkHost) { + this.linkHost = linkHost; + } + + public boolean isApplicationFeed() { + return applicationFeed; + } + public void setApplicationFeed(boolean applicationFeed) { + this.applicationFeed = applicationFeed; + } + public boolean isMultiFileUpload() { + return multiFileUpload; + } + public void setMultiFileUpload(boolean multiFileUpload) { + this.multiFileUpload = multiFileUpload; + } + @Override + public String toString() { + return "Post [key=" + key + ", type=" + type + ", entityId=" + entityId + + ", time=" + time + ", vreid=" + vreid + ", uri=" + uri + + ", uriThumbnail=" + uriThumbnail + ", description=" + + description + ", privacy=" + privacy + ", fullName=" + + fullName + ", email=" + email + ", thumbnailURL=" + + thumbnailURL + ", commentsNo=" + commentsNo + ", likesNo=" + + likesNo + ", linkTitle=" + linkTitle + ", linkDescription=" + + linkDescription + ", linkHost=" + linkHost + + ", applicationFeed=" + applicationFeed + + ", multiFileUpload=" + multiFileUpload + "]"; + } + +} diff --git a/src/main/java/org/gcube/portal/databook/shared/PostType.java b/src/main/java/org/gcube/portal/databook/shared/PostType.java new file mode 100644 index 0000000..b86c0c7 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/PostType.java @@ -0,0 +1,18 @@ +package org.gcube.portal.databook.shared; + +/** + * @author Massimiliano Assante ISTI-CNR + * + */ +public enum PostType { + JOIN, SHARE, PUBLISH, TWEET, CONNECTED, + /** + * Special case used when accounting + */ + ACCOUNTING, + /** + * Special case used when a Feed is removed + */ + DISABLED; +} + diff --git a/src/main/java/org/gcube/portal/databook/shared/PrivacyLevel.java b/src/main/java/org/gcube/portal/databook/shared/PrivacyLevel.java new file mode 100644 index 0000000..9f21298 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/PrivacyLevel.java @@ -0,0 +1,9 @@ +package org.gcube.portal.databook.shared; +/** + * @author Massimiliano Assante ISTI-CNR + * + * @version 1.0 July 6th 2012 + */ +public enum PrivacyLevel { + PRIVATE, CONNECTION, VRES, SINGLE_VRE, PORTAL, PUBLIC; +} diff --git a/src/main/java/org/gcube/portal/databook/shared/RangeFeeds.java b/src/main/java/org/gcube/portal/databook/shared/RangeFeeds.java new file mode 100644 index 0000000..50d90bb --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/RangeFeeds.java @@ -0,0 +1,40 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.ArrayList; +/** + * + * @author Massimiliano Assante, ISTI-CNR + * @deprecated use RangePosts + */ +@SuppressWarnings("serial") +public class RangeFeeds implements Serializable { + + private int lastReturnedFeedTimelineIndex; + private ArrayList feeds; + + public RangeFeeds() { + super(); + } + + public RangeFeeds(int lastReturnedFeedTimelineIndex, ArrayList feeds) { + super(); + this.lastReturnedFeedTimelineIndex = lastReturnedFeedTimelineIndex; + this.feeds = feeds; + } + + public int getLastReturnedFeedTimelineIndex() { + return lastReturnedFeedTimelineIndex; + } + public void setLastReturnedFeedTimelineIndex(int lastReturnedFeedTimelineIndex) { + this.lastReturnedFeedTimelineIndex = lastReturnedFeedTimelineIndex; + } + public ArrayList getFeeds() { + return feeds; + } + public void setFeeds(ArrayList feeds) { + this.feeds = feeds; + } + + +} diff --git a/src/main/java/org/gcube/portal/databook/shared/RangePosts.java b/src/main/java/org/gcube/portal/databook/shared/RangePosts.java new file mode 100644 index 0000000..4e645b5 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/RangePosts.java @@ -0,0 +1,40 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.ArrayList; +/** + * + * @author Massimiliano Assante, ISTI-CNR + * + */ +@SuppressWarnings("serial") +public class RangePosts implements Serializable { + + private int lastReturnedPostTimelineIndex; + private ArrayList posts; + + public RangePosts() { + super(); + } + + public RangePosts(int lastReturnedPostTimelineIndex, ArrayList feeds) { + super(); + this.lastReturnedPostTimelineIndex = lastReturnedPostTimelineIndex; + this.posts = feeds; + } + + public int getLastReturnedPostTimelineIndex() { + return lastReturnedPostTimelineIndex; + } + public void setLastReturnedPostTimelineIndex(int lastReturnedPostTimelineIndex) { + this.lastReturnedPostTimelineIndex = lastReturnedPostTimelineIndex; + } + public ArrayList getPosts() { + return posts; + } + public void setPosts(ArrayList posts) { + this.posts = posts; + } + + +} diff --git a/src/main/java/org/gcube/portal/databook/shared/RunningJob.java b/src/main/java/org/gcube/portal/databook/shared/RunningJob.java new file mode 100644 index 0000000..a69cd74 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/RunningJob.java @@ -0,0 +1,83 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; + +/** + * The RunningJob class. + * @author Massimiliano Assante, ISTI-CNR (massimiliano.assante@isti.cnr.it) + * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + */ +@SuppressWarnings("serial") +public class RunningJob implements Serializable { + + private String jobId; + private String jobName; + private JobStatusType status; + private String message; + private String serviceName; // i.e., Dataminer, SmartExecutor.. + + public RunningJob() { + super(); + } + + /** Buind a RunningJob object. + * @param jobId + * @param jobName + * @param status + * @param message + * @param serviceName + */ + public RunningJob(String jobId, String jobName, JobStatusType status, + String message, String serviceName) { + super(); + this.jobId = jobId; + this.jobName = jobName; + this.status = status; + this.message = message; + this.serviceName = serviceName; + } + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getJobId() { + return jobId; + } + public void setJobId(String jobId) { + this.jobId = jobId; + } + public String getJobName() { + return jobName; + } + public void setJobName(String jobName) { + this.jobName = jobName; + } + public JobStatusType getStatus() { + return status; + } + public void setStatus(JobStatusType status) { + this.status = status; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + @Override + public String toString() { + return "RunningJob [" + (jobId != null ? "jobId=" + jobId + ", " : "") + + (jobName != null ? "jobName=" + jobName + ", " : "") + + (status != null ? "status=" + status + ", " : "") + + (message != null ? "message=" + message + ", " : "") + + (serviceName != null ? "serviceName=" + serviceName : "") + + "]"; + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ShowUserStatisticAction.java b/src/main/java/org/gcube/portal/databook/shared/ShowUserStatisticAction.java new file mode 100644 index 0000000..25278f6 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ShowUserStatisticAction.java @@ -0,0 +1,25 @@ +package org.gcube.portal.databook.shared; + +/** + * Enum class that specify the possible actions to take when the GCubeSocialNetworking.SHOW_STATISTICS_ACTION_OID parameter + * is found in the page url + * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + */ +public enum ShowUserStatisticAction { + + POSTS_MADE_BY_USER("Your recent posts"), + LIKES_MADE_BY_USER("Posts you liked"), + COMMENTS_MADE_BY_USER("Posts you commented"), + LIKES_GOT_BY_USER("Likes to your posts"), + COMMENTS_GOT_BY_USER("Replies to your posts"); + + private final String actionHumanFriendly; + + private ShowUserStatisticAction(String s) { + actionHumanFriendly = s; + } + + public String getHumanFriendlyAction() { + return this.actionHumanFriendly; + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/UserInfo.java b/src/main/java/org/gcube/portal/databook/shared/UserInfo.java new file mode 100644 index 0000000..74f9c2a --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/UserInfo.java @@ -0,0 +1,121 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * @author Massimiliano Assante ISTI-CNR + */ +@SuppressWarnings("serial") +public class UserInfo implements Serializable { + + public transient final static String USER_INFO_ATTR = "USER_INFO_ATTR"; + + private String username; + + private String fullName; + + private String avatarId; + + private String emailaddress; + + private String accountURL; + + private boolean male; + + private boolean admin; + + private HashMap ownVREs; + + public UserInfo() { + super(); + } + + public UserInfo(String username, String fullName, String avatarId, + String emailaddress, String accountURL, boolean male, + boolean admin, HashMap ownVREs) { + super(); + this.username = username; + this.fullName = fullName; + this.avatarId = avatarId; + this.emailaddress = emailaddress; + this.accountURL = accountURL; + this.male = male; + this.admin = admin; + this.ownVREs = ownVREs; + } + + public String getAccountURL() { + return accountURL; + } + + public void setAccountURL(String accountURL) { + this.accountURL = accountURL; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getAvatarId() { + return avatarId; + } + + public void setAvatarId(String avatarId) { + this.avatarId = avatarId; + } + + public String getEmailaddress() { + return emailaddress; + } + + public void setEmailaddress(String emailaddress) { + this.emailaddress = emailaddress; + } + + public boolean isMale() { + return male; + } + + public void setMale(boolean male) { + this.male = male; + } + + public HashMap getOwnVREs() { + return ownVREs; + } + + public void setOwnVREs(HashMap vreMap) { + this.ownVREs = vreMap; + } + + public boolean isAdmin() { + return admin; + } + + public void setAdmin(boolean admin) { + this.admin = admin; + } + + @Override + public String toString() { + return "UserInfo [username=" + username + ", fullName=" + fullName + + ", avatarId=" + avatarId + ", emailaddress=" + emailaddress + + ", accountURL=" + accountURL + ", male=" + male + ", admin=" + + admin + ", ownVREs=" + ownVREs + "]"; + } + + +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java new file mode 100644 index 0000000..536e6a6 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class ColumnNameNotFoundException extends Exception { + public ColumnNameNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.java new file mode 100644 index 0000000..605d8f7 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class CommentIDNotFoundException extends Exception { + public CommentIDNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java new file mode 100644 index 0000000..52c2dce --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java @@ -0,0 +1,9 @@ +package org.gcube.portal.databook.shared.ex; + + +@SuppressWarnings("serial") +public class FeedIDNotFoundException extends Exception { + public FeedIDNotFoundException(String message, String postId) { + super("The Post having id: " + postId + " is not present in the database: " + message); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.java new file mode 100644 index 0000000..a39d6dc --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class FeedTypeNotFoundException extends Exception { + public FeedTypeNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java new file mode 100644 index 0000000..a7d5cb0 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class InviteIDNotFoundException extends Exception { + public InviteIDNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java new file mode 100644 index 0000000..5f4f9c2 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class InviteStatusNotFoundException extends Exception { + public InviteStatusNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.java new file mode 100644 index 0000000..f0fe653 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class LikeIDNotFoundException extends Exception { + public LikeIDNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java new file mode 100644 index 0000000..e70f779 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class NotificationChannelTypeNotFoundException extends Exception { + public NotificationChannelTypeNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java new file mode 100644 index 0000000..13c0ebb --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class NotificationIDNotFoundException extends Exception { + public NotificationIDNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.java new file mode 100644 index 0000000..a4700e4 --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class NotificationTypeNotFoundException extends Exception { + public NotificationTypeNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java b/src/main/java/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java new file mode 100644 index 0000000..10fc82b --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class PrivacyLevelTypeNotFoundException extends Exception { + public PrivacyLevelTypeNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java b/src/main/java/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java new file mode 100644 index 0000000..7afbe1d --- /dev/null +++ b/src/main/java/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class TooManyRunningClustersException extends Exception { + public TooManyRunningClustersException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/target/antrun/build-printOutputDirectories.xml b/target/antrun/build-printOutputDirectories.xml new file mode 100644 index 0000000..d27fb49 --- /dev/null +++ b/target/antrun/build-printOutputDirectories.xml @@ -0,0 +1,8 @@ + + + + ******** Displaying value of *.outputDirectory properties ******** + project.metainf.outputDirectory=${project.metainf.outputDirectory} + project.webinf.outputDirectory=${project.webinf.outputDirectory} + + diff --git a/target/antrun/build-seOuttputDirectories.xml b/target/antrun/build-seOuttputDirectories.xml new file mode 100644 index 0000000..35647b1 --- /dev/null +++ b/target/antrun/build-seOuttputDirectories.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/target/classes/META-INF/LICENSE.md b/target/classes/META-INF/LICENSE.md new file mode 100644 index 0000000..c25566d --- /dev/null +++ b/target/classes/META-INF/LICENSE.md @@ -0,0 +1,311 @@ +#European Union Public Licence V.1.1 + +##*EUPL © the European Community 2007* + + +This **European Union Public Licence** (the **“EUPL”**) applies to the Work or Software +(as defined below) which is provided under the terms of this Licence. Any use of +the Work, other than as authorised under this Licence is prohibited (to the +extent such use is covered by a right of the copyright holder of the Work). + +The Original Work is provided under the terms of this Licence when the Licensor +(as defined below) has placed the following notice immediately following the +copyright notice for the Original Work: + +**Licensed under the EUPL V.1.1** + +or has expressed by any other mean his willingness to license under the EUPL. + + + +##1. Definitions + +In this Licence, the following terms have the following meaning: + +- The Licence: this Licence. + +- The Original Work or the Software: the software distributed and/or + communicated by the Licensor under this Licence, available as Source Code and + also as Executable Code as the case may be. + +- Derivative Works: the works or software that could be created by the Licensee, + based upon the Original Work or modifications thereof. This Licence does not + define the extent of modification or dependence on the Original Work required + in order to classify a work as a Derivative Work; this extent is determined by + copyright law applicable in the country mentioned in Article 15. + +- The Work: the Original Work and/or its Derivative Works. + +- The Source Code: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- The Executable Code: any code which has generally been compiled and which is + meant to be interpreted by a computer as a program. + +- The Licensor: the natural or legal person that distributes and/or communicates + the Work under the Licence. + +- Contributor(s): any natural or legal person who modifies the Work under the + Licence, or otherwise contributes to the creation of a Derivative Work. + +- The Licensee or “You”: any natural or legal person who makes any usage of the + Software under the terms of the Licence. + +- Distribution and/or Communication: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, on-line or off-line, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + + + +##2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a world-wide, royalty-free, non-exclusive, +sub-licensable licence to do the following, for the duration of copyright vested +in the Original Work: + +- use the Work in any circumstance and for all usage, reproduce the Work, modify +- the Original Work, and make Derivative Works based upon the Work, communicate +- to the public, including the right to make available or display the Work or +- copies thereof to the public and perform publicly, as the case may be, the +- Work, distribute the Work or copies thereof, lend and rent the Work or copies +- thereof, sub-license rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make effective +the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non exclusive usage rights to +any patents held by the Licensor, to the extent necessary to make use of the +rights granted on the Work under this Licence. + + + +##3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, in +a notice following the copyright notice attached to the Work, a repository where +the Source Code is easily and freely accessible for as long as the Licensor +continues to distribute and/or communicate the Work. + + + +##4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits from +any exception or limitation to the exclusive rights of the rights owners in the +Original Work or Software, of the exhaustion of those rights or of other +applicable limitations thereto. + + + +##5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: the Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and a +copy of the Licence with every copy of the Work he/she distributes and/or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes and/or communicates copies of the +Original Works or Derivative Works based upon the Original Work, this +Distribution and/or Communication will be done under the terms of this Licence +or of a later version of this Licence unless the Original Work is expressly +distributed only under this version of the Licence. The Licensee (becoming +Licensor) cannot offer or impose any additional terms or conditions on the Work +or Derivative Work that alter or restrict the terms of the Licence. + +Compatibility clause: If the Licensee Distributes and/or Communicates Derivative +Works or copies thereof based upon both the Original Work and another work +licensed under a Compatible Licence, this Distribution and/or Communication can +be done under the terms of this Compatible Licence. For the sake of this clause, +“Compatible Licence” refers to the licences listed in the appendix attached to +this Licence. Should the Licensee’s obligations under the Compatible Licence +conflict with his/her obligations under this Licence, the obligations of the +Compatible Licence shall prevail. + +Provision of Source Code: When distributing and/or communicating copies of the +Work, the Licensee will provide a machine-readable copy of the Source Code or +indicate a repository where this Source will be easily and freely available for +as long as the Licensee continues to distribute and/or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade names, +trademarks, service marks, or names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the copyright notice. + + + +##6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she brings +to the Work are owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + + + +##7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +contributors. It is not a finished work and may therefore contain defects or +“bugs” inherent to this type of software development. + +For the above reason, the Work is provided under the Licence on an “as is” basis +and without warranties of any kind concerning the Work, including without +limitation merchantability, fitness for a particular purpose, absence of defects +or errors, accuracy, non-infringement of intellectual property rights other than +copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a condition +for the grant of any rights to the Work. + + + +##8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the use +of the Work, including without limitation, damages for loss of goodwill, work +stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such +damage. However, the Licensor will be liable under statutory product liability +laws as far such laws apply to the Work. + + + +##9. Additional agreements + +While distributing the Original Work or Derivative Works, You may choose to +conclude an additional agreement to offer, and charge a fee for, acceptance of +support, warranty, indemnity, or other liability obligations and/or services +consistent with this Licence. However, in accepting such obligations, You may +act only on your own behalf and on your sole responsibility, not on behalf of +the original Licensor or any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred +by, or claims asserted against such Contributor by the fact You have accepted +any such warranty or additional liability. + + + +##10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon “I agree” +placed under the bottom of a window displaying the text of this Licence or by +affirming consent in any other similar way, in accordance with the rules of +applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this Licence, +such as the use of the Work, the creation by You of a Derivative Work or the +Distribution and/or Communication by You of the Work or copies thereof. + + + +##11. Information to the public + +In case of any Distribution and/or Communication of the Work by means of +electronic communication by You (for example, by offering to download the Work +from a remote location) the distribution channel or media (for example, a +website) must at least provide to the public the information requested by the +applicable law regarding the Licensor, the Licence and the way it may be +accessible, concluded, stored and reproduced by the Licensee. + + + +##12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + + + +##13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work licensed hereunder. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed and/or reformed so as necessary to make +it valid and enforceable. + +The European Commission may publish other linguistic versions and/or new +versions of this Licence, so far this is required and reasonable, without +reducing the scope of the rights granted by the Licence. New versions of the +Licence will be published with a unique version number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + + + +##14. Jurisdiction + +Any litigation resulting from the interpretation of this License, arising +between the European Commission, as a Licensor, and any Licensee, will be +subject to the jurisdiction of the Court of Justice of the European Communities, +as laid down in article 238 of the Treaty establishing the European Community. + +Any litigation arising between Parties, other than the European Commission, and +resulting from the interpretation of this License, will be subject to the +exclusive jurisdiction of the competent court where the Licensor resides or +conducts its primary business. + + + +##15. Applicable Law + +This Licence shall be governed by the law of the European Union country where +the Licensor resides or has his registered office. + +This licence shall be governed by the Belgian law if: + +- a litigation arises between the European Commission, as a Licensor, and any +- Licensee; the Licensor, other than the European Commission, has no residence +- or registered office inside a European Union country. + + +--- + + +##Appendix + + +**“Compatible Licences”** according to article 5 EUPL are: + + +- GNU General Public License (GNU GPL) v. 2 + +- Open Software License (OSL) v. 2.1, v. 3.0 + +- Common Public License v. 1.0 + +- Eclipse Public License v. 1.0 + +- Cecill v. 2.0 \ No newline at end of file diff --git a/target/classes/META-INF/MANIFEST.MF b/target/classes/META-INF/MANIFEST.MF new file mode 100644 index 0000000..39bdc1c --- /dev/null +++ b/target/classes/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Build-Jdk-Spec: 15 +Specification-Title: gCube Social Networking Library +Specification-Version: 1.18 +Implementation-Title: gCube Social Networking Library +Implementation-Version: 1.18.0-SNAPSHOT +Build-Time: 20231127-152422 +Created-By: Maven Integration for Eclipse +SCM-Branch: +SCM-Revision: +SCM-Revision-URL: https://code-repo.d4science.org/gCubeSystem/social-net + working-library/commit/${buildNumber} + diff --git a/target/classes/META-INF/maven/org.gcube.portal/social-networking-library/pom.properties b/target/classes/META-INF/maven/org.gcube.portal/social-networking-library/pom.properties new file mode 100644 index 0000000..44ee4a7 --- /dev/null +++ b/target/classes/META-INF/maven/org.gcube.portal/social-networking-library/pom.properties @@ -0,0 +1,7 @@ +#Generated by Maven Integration for Eclipse +#Mon Nov 27 16:24:30 CET 2023 +m2e.projectLocation=/Users/massi/workspace/social-networking-library +m2e.projectName=social-networking-library +groupId=org.gcube.portal +artifactId=social-networking-library +version=1.18.0-SNAPSHOT diff --git a/target/classes/META-INF/maven/org.gcube.portal/social-networking-library/pom.xml b/target/classes/META-INF/maven/org.gcube.portal/social-networking-library/pom.xml new file mode 100644 index 0000000..678afc0 --- /dev/null +++ b/target/classes/META-INF/maven/org.gcube.portal/social-networking-library/pom.xml @@ -0,0 +1,152 @@ + + 4.0.0 + + maven-parent + org.gcube.tools + 1.1.0 + + + + org.gcube.portal + social-networking-library + 1.18.0-SNAPSHOT + gCube Social Networking Library + + The gCube Social Networking Library is the 'bridge' between your gCube Applications and the social networking facilities. + The social networking facilities exploit a NoSQL data store for their storage. Specifically an Apache Cassandra data store. + + + scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId} + scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId} + https://code-repo.d4science.org/gCubeSystem/${project.artifactId} + + + 1.8 + 1.8 + 2.8.1 + UTF-8 + UTF-8 + 4.13.0 + 1.2.3 + + + + + org.gcube.distribution + maven-portal-bom + 3.6.4 + pom + import + + + + + + org.gcube.social-networking + social-service-client + [1.3.0-SNAPSHOT, 2.0.0) + + + com.google + gwt-jsonmaker + 1.2.1 + + + org.gcube.resources.discovery + ic-client + provided + + + org.gcube.common.portal + portal-manager + provided + + + com.sun.mail + javax.mail + provided + + + junit + junit + 4.8 + + + com.google.gwt + gwt-user + ${gwtVersion} + provided + + + org.slf4j + slf4j-log4j12 + + + org.slf4j + slf4j-api + + + commons-lang + commons-lang + 2.6 + + + + + + src/main/java + + **/*.* + + + + + + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + org.apache.maven.plugins + maven-javadoc-plugin + + -Xdoclint:none + -Xdoclint:none + + 3.1.0 + + + generate-doc + install + + jar + + + + + + + + \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/GCubeSocialNetworking.gwt.xml b/target/classes/org/gcube/portal/databook/GCubeSocialNetworking.gwt.xml new file mode 100644 index 0000000..d40b2ea --- /dev/null +++ b/target/classes/org/gcube/portal/databook/GCubeSocialNetworking.gwt.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/classes/org/gcube/portal/databook/client/GCubeSocialNetworking.class b/target/classes/org/gcube/portal/databook/client/GCubeSocialNetworking.class new file mode 100644 index 0000000000000000000000000000000000000000..663f4ff6175845a108e461cfd90de1703fb491ec GIT binary patch literal 866 zcmbV~U2oGc6o!wxt}R_hxAD0SHU>lDL&7%*A%T!W$l6G4Q`Kp?tX$Wm-qIL34i!I( zD)W-6dPPpY` zttCQ67#146!$qH-{ zILK0I{0Ua4J}AMh(n*gSK9g1&0$VMIwL+(vdsg5ofx{_Jr=HPU zF;A@$OmZWpYh?}A3f_-c=!8BCeV2_KH}r$<(&jpW<8-R$11yzUtT8uC9dW7H-DW=+ z^hO=8^VaLLrSum5p_P2LHgV~-N|b#=VB^u_A%UW+C$b6~aHj^hVV^*~trFSIW@BkW zK8|I6vRd$X$c@VRcd%%uDkbo;{eO1=dsEX%M^Ca?wl$v+s4|@yAx~AFvhmN0^DOT$ z90S&l?#hKu|`Q$4c sd|9Npi(_dKtiU0zYs(FA1ox1zZ5QIF3&z-GVSPnNE`;}SdjTH&0?X3V)c^nh literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/client/GCubeSocialNetworking.java b/target/classes/org/gcube/portal/databook/client/GCubeSocialNetworking.java new file mode 100644 index 0000000..565127d --- /dev/null +++ b/target/classes/org/gcube/portal/databook/client/GCubeSocialNetworking.java @@ -0,0 +1,17 @@ +package org.gcube.portal.databook.client; + +import com.google.gwt.core.client.EntryPoint; + +/** + * Entry point classes define onModuleLoad() and instances the HandlerManager for IPC + */ +public class GCubeSocialNetworking implements EntryPoint { + public static final String USER_PROFILE_OID = "userIdentificationParameter"; + public static final String HASHTAG_OID = "hashtagIdentificationParameter"; + public static final String SEARCH_OID = "elasticSearchIdentificationParameter"; + public static final String SHOW_STATISTICS_ACTION_OID = "showUserStatisticsActionParameter"; // see ShowUserStatisticAction + public static final String GROUP_MEMBERS_OID = "teamIdentificationParameter"; + public void onModuleLoad() { + } + +} diff --git a/target/classes/org/gcube/portal/databook/client/util/Encoder.class b/target/classes/org/gcube/portal/databook/client/util/Encoder.class new file mode 100644 index 0000000000000000000000000000000000000000..9fbdaca5b86f98e8407ce93e5cda1ee8f2663cbb GIT binary patch literal 397 zcmb7Au};G<6ug(F4Gn>o@&zoYMFKBuMO_d~5e!A$9mfhT!A8d6znG91_y9f%@mwk~ zFtObEy?4*P^XJ$52Y_=NW=II9&Nre_U8Tj7^Fg+vmO)m|JqXnrZG-57X~mUQuGT(7 zN*J%@ixjQ2jkvAWS_Q)3!dMd)gx++vBBYlr&e6lLKpz9bs5DmJbdQzxcd}|VVNyCJ z+m-Yt*4t(p?#(knl>ag{=lAu-AK`df{<>QRZ)`K4{cZ6^tz#lWzI2^e`r1TS#Wv?z zyaY$!K>Sx=q!@%T<4Q0SbN}QGJFk35kTb?HSg^}j{0Nx$02*Q+qYaNE^Xz~z!Q>l3 CfL=ua literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/client/util/Encoder.java b/target/classes/org/gcube/portal/databook/client/util/Encoder.java new file mode 100644 index 0000000..312a720 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/client/util/Encoder.java @@ -0,0 +1,15 @@ +package org.gcube.portal.databook.client.util; +/** + * simply encode base64 strings + * @author massi + * + */ +public class Encoder { + public static native String encode(String toEncode) /*-{ + return btoa(toEncode); + }-*/; + + public static native String decode(String toDecode) /*-{ + return atob(toDecode); +}-*/; +} diff --git a/target/classes/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.class b/target/classes/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..8fee6d1bdfbe5f6a1322b11f6e767538cdc9563f GIT binary patch literal 29549 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java b/target/classes/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java new file mode 100644 index 0000000..20724f1 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java @@ -0,0 +1,945 @@ +package org.gcube.portal.databook.server; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import javax.mail.internet.AddressException; + +import org.gcube.portal.databook.shared.*; +import org.gcube.portal.databook.shared.ex.ColumnNameNotFoundException; +import org.gcube.portal.databook.shared.ex.CommentIDNotFoundException; +import org.gcube.portal.databook.shared.ex.FeedIDNotFoundException; +import org.gcube.portal.databook.shared.ex.FeedTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.InviteIDNotFoundException; +import org.gcube.portal.databook.shared.ex.InviteStatusNotFoundException; +import org.gcube.portal.databook.shared.ex.LikeIDNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationChannelTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationIDNotFoundException; +import org.gcube.portal.databook.shared.ex.NotificationTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.PrivacyLevelTypeNotFoundException; +import org.gcube.social_networking.social_networking_client_library.CommentClient; +import org.gcube.social_networking.social_networking_client_library.HashTagClient; +import org.gcube.social_networking.social_networking_client_library.InviteClient; +import org.gcube.social_networking.social_networking_client_library.LikeClient; +import org.gcube.social_networking.social_networking_client_library.NotificationClient; +import org.gcube.social_networking.social_networking_client_library.PostClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Massimiliano Assante ISTI-CNR + * @author Costantino Perciante ISTI-CNR + * This class is used for querying and adding data to Cassandra via Astyanax High Level API + */ +public final class DBCassandraAstyanaxImpl implements DatabookStore { + + /** + * logger + */ + private static final Logger _log = LoggerFactory.getLogger(DBCassandraAstyanaxImpl.class); + private static PostClient postClient; + private static NotificationClient notificationClient; + private static HashTagClient hashTagClient; + private static InviteClient inviteClient; + private static CommentClient commentClient; + private static LikeClient likeClient; + + + /** + * use this constructor carefully from test classes + * @param dropSchema set true if you want do drop the current and set up new one + */ + protected DBCassandraAstyanaxImpl(boolean dropSchema) { + try { + postClient = new PostClient(); + notificationClient = new NotificationClient(); + hashTagClient = new HashTagClient(); + commentClient = new CommentClient(); + inviteClient = new InviteClient(); + likeClient = new LikeClient(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + /** + * public constructor, no dropping schema is allowed + */ + public DBCassandraAstyanaxImpl() { + try { + postClient = new PostClient(); + notificationClient = new NotificationClient(); + hashTagClient = new HashTagClient(); + commentClient = new CommentClient(); + inviteClient = new InviteClient(); + likeClient = new LikeClient(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + /** + * public constructor, no dropping schema is allowed, infrastructureName is given. + */ + public DBCassandraAstyanaxImpl(String infrastructureName) { + try { + postClient = new PostClient(); + notificationClient = new NotificationClient(); + hashTagClient = new HashTagClient(); + commentClient = new CommentClient(); + inviteClient = new InviteClient(); + likeClient = new LikeClient(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /* + * + ********************** FRIENDSHIPS (CONNECTIONS) *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public boolean requestFriendship(String from, String to) { + return true; + } + /** + * {@inheritDoc} + */ + @Override + public boolean approveFriendship(String from, String to) { + return true; + } + /** + * {@inheritDoc} + */ + @Override + public boolean denyFriendship(String from, String to) { + return true; + } + /** + * {@inheritDoc} + */ + @Override + public List getFriends(String userid) { + ArrayList toReturn = new ArrayList(); + return toReturn; + } + /** + * {@inheritDoc} + */ + @Override + public List getPendingFriendRequests(String userid) { + ArrayList toReturn = new ArrayList(); + return toReturn; + } + /* + * + ********************** FEEDS *********************** + * + */ + + private static Post feed2post(Feed feed){ + Post post = new Post(feed.getKey(), PostType.valueOf(feed.getType().toString()), feed.getEntityId(), feed.getTime(), + feed.getVreid(), feed.getUri(), feed.getUriThumbnail(), feed.getDescription(), feed.getPrivacy(), + feed.getFullName(), feed.getEmail(), feed.getThumbnailURL(), feed.getCommentsNo(), + feed.getLikesNo(), feed.getLinkTitle(), feed.getLinkDescription(), feed.getLinkHost(), feed.isApplicationFeed(), feed.isMultiFileUpload()); + return post; + } + + private static Feed post2feed(Post post){ + Feed feed = new Feed(post.getKey(), FeedType.valueOf(post.getType().toString()), post.getEntityId(), post.getTime(), + post.getVreid(), post.getUri(), post.getUriThumbnail(), post.getDescription(), post.getPrivacy(), + post.getFullName(), post.getEmail(), post.getThumbnailURL(), post.getCommentsNo(), + post.getLikesNo(), post.getLinkTitle(), post.getLinkDescription(), post.getLinkHost(), post.isApplicationFeed(), post.isMultiFileUpload()); + return feed; + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean saveUserFeed(Feed post) { + return saveUserPost(feed2post(post)); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveUserPost(Post post) { + return postClient.saveUserPostLib(post); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean saveUserFeed(Feed feed, List attachments) { + return saveUserPost(feed2post(feed), attachments); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveUserPost(Post post, List attachments) { + return postClient.saveUserPostLib(post, attachments); + } + + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public boolean saveAppFeed(Feed post) { + return saveAppPost(feed2post(post)); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveAppPost(Post post) { + return postClient.saveAppPostLib(post); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean saveAppFeed(Feed feed, List attachments) { + return saveAppPost(feed2post(feed), attachments); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveAppPost(Post post, List attachments) { + return postClient.saveAppPostLib(post, attachments); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean saveFeedToVRETimeline(String feedKey, String vreid) throws FeedIDNotFoundException { + return savePostToVRETimeline(feedKey, vreid); + } + /** + * {@inheritDoc} + */ + @Override + public boolean savePostToVRETimeline(String postKey, String vreid) throws FeedIDNotFoundException { + return postClient.savePostToVRETimelineLib(postKey, vreid); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public Feed readFeed(String feedid) + throws PrivacyLevelTypeNotFoundException, + FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + + return post2feed(readPost(feedid)); + } + /** + * {@inheritDoc} + */ + @Override + public Post readPost(String postid) + throws PrivacyLevelTypeNotFoundException, + FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + return postClient.readPostLib(postid); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getRecentFeedsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException { + Date now = new Date(); + if (timeInMillis > now.getTime()) + throw new IllegalArgumentException("the timeInMillis must be before today"); + List posts = getRecentPostsByUserAndDate(userid, timeInMillis); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + */ + @Override + public List getRecentPostsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException { + Date now = new Date(); + if (timeInMillis > now.getTime()) + throw new IllegalArgumentException("the timeInMillis must be before today"); + + return postClient.getRecentPostsByUserAndDateLib(userid, timeInMillis); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public boolean deleteFeed(String feedId) throws FeedIDNotFoundException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException { + return deletePost(feedId); + } + /** + * {@inheritDoc} + */ + @Override + public boolean deletePost(String postid) throws FeedIDNotFoundException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException { + return postClient.deletePostLib(postid); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public List getAllFeedsByUser(String userid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + List posts = getAllPostsByUser(userid); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + */ + @Override + public List getAllPostsByUser(String userid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getAllPostsByUserLib(userid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllFeedsByApp(String appid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + List posts = getAllPostsByApp(appid); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + */ + @Override + public List getAllPostsByApp(String appid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getAllPostsByAppLib(appid); + } + /** + * {@inheritDoc} + * @throws Exception + */ + @Deprecated + @Override + public List getRecentCommentedFeedsByUserAndDate(String userid, + long timeInMillis) throws Exception { + List posts = getRecentCommentedPostsByUserAndDate(userid, timeInMillis); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + * @throws Exception + */ + @Override + public List getRecentCommentedPostsByUserAndDate(String userid, + long timeInMillis) throws Exception { + return postClient.getRecentCommentedPostsByUserAndDateLib(userid, timeInMillis); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public List getAllPortalPrivacyLevelFeeds() throws FeedTypeNotFoundException, ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException { + List posts = getAllPortalPrivacyLevelPosts(); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + @Override + public List getAllPortalPrivacyLevelPosts() throws FeedTypeNotFoundException, ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException { + return postClient.getAllPortalPrivacyLevelPostsLib(); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getRecentFeedsByUser(String userid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + List posts = getRecentPostsByUser(userid, quantity); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + @Override + public List getRecentPostsByUser(String userid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getRecentPostsByUserLib(userid, quantity); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getAllFeedsByVRE(String vreid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + List posts = getAllPostsByVRE(vreid); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + return feeds; + } + /** + * {@inheritDoc} + */ + @Override + public List getAllPostsByVRE(String vreid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getAllPostsByVRELib(vreid); + } + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public List getRecentFeedsByVRE(String vreid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + _log.info("\n\n in getRecentFeedsByVRE"); + List posts = getRecentPostsByVRE(vreid, quantity); + _log.info("length of vre posts = " + posts.size()); + List feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + _log.info("length of vre feeds = " + feeds.size()); + return feeds; + } + @Override + public List getRecentPostsByVRE(String vreid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + _log.info("\n\n in getRecentPostsByVRE"); + return postClient.getRecentPostsByVRELib(vreid, quantity); + } + /** + * {@inheritDoc} + */ + @Override + public RangeFeeds getRecentFeedsByVREAndRange(String vreid, int from, int quantity) throws IllegalArgumentException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + RangePosts rangePosts = getRecentPostsByVREAndRange(vreid, from, quantity); + List posts = rangePosts.getPosts(); + ArrayList feeds = new ArrayList<>(); + for(Post post: posts){ + feeds.add(post2feed(post)); + } + RangeFeeds rangeFeeds = new RangeFeeds(rangePosts.getLastReturnedPostTimelineIndex(), feeds); + return rangeFeeds; + } + /** + * {@inheritDoc} + */ + @Override + public RangePosts getRecentPostsByVREAndRange(String vreid, int from, int quantity) throws IllegalArgumentException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + return postClient.getRecentPostsByVREAndRangeLib(vreid, from, quantity); + } + + /* + * + ********************** NOTIFICATIONS *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public boolean saveNotification(Notification n) { + return notificationClient.saveNotificationLib(n); + } + + /** + * {@inheritDoc} + */ + @Override + public Notification readNotification(String notificationid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.readNotificationLib(notificationid); + } + /** + * {@inheritDoc} + */ + @Override + public boolean setNotificationRead(String notificationidToSet) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.setNotificationReadLib(notificationidToSet); + } + + /** + * {@inheritDoc} + */ + @Override + public List getAllNotificationByUser(String userid, int limit) throws NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.getAllNotificationByUserLib(userid, limit); + } + /** + * {@inheritDoc} + */ + @Override + public List getUnreadNotificationsByUser(String userid) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException { + return notificationClient.getUnreadNotificationsByUserLib(userid); + } + /** + * {@inheritDoc} + */ + @Override + public List getRangeNotificationsByUser(String userid,int from, int quantity) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException { + return notificationClient.getRangeNotificationsByUserLib(userid, from, quantity); + } + /** + * {@inheritDoc} + */ + @Override + public boolean setAllNotificationReadByUser(String userid) throws NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.setAllNotificationReadByUserLib(userid); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean checkUnreadNotifications(String userid) throws NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.checkUnreadNotificationsLib(userid); + } + /** + * {@inheritDoc} + */ + @Override + public boolean checkUnreadMessagesNotifications(String userid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException { + return notificationClient.checkUnreadMessagesNotificationsLib(userid); + } + /* + * + ********************** NOTIFICATION SETTINGS *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public List getUserNotificationChannels(String userid, NotificationType notificationType) throws NotificationChannelTypeNotFoundException, NotificationTypeNotFoundException { + return notificationClient.getUserNotificationChannelsLib(userid, notificationType); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean setUserNotificationPreferences(String userid, Map enabledChannels) { + return notificationClient.setUserNotificationPreferencesLib(userid, enabledChannels); + } + /** + * {@inheritDoc} + * + * by default Workspace and Calendar Notifications are set to Portal + */ + @Override + public Map getUserNotificationPreferences(String userid) throws NotificationTypeNotFoundException, NotificationChannelTypeNotFoundException { + return notificationClient.getUserNotificationPreferencesLib(userid); + } + /* + * + ********************** COMMENTS *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public boolean addComment(Comment comment) throws FeedIDNotFoundException { + return commentClient.addCommentLib(comment)!=null; + } + /** + * {@inheritDoc} + */ + public Comment readCommentById(String commentId) throws CommentIDNotFoundException { + return commentClient.readCommentByIdLib(commentId); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getAllCommentByFeed(String feedid) { + return getAllCommentByPost(feedid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllCommentByPost(String postid) { + return commentClient.getAllCommentsByPostIdLib(postid); + } + + /** + * {@inheritDoc} + * @throws Exception + */ + @Override + public List getRecentCommentsByUserAndDate(final String userid, + final long timeInMillis) throws Exception { + + return commentClient.getRecentCommentsByUserAndDateLib(userid, timeInMillis); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean editComment(Comment comment2Edit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, CommentIDNotFoundException, FeedIDNotFoundException { + return commentClient.editCommentLib(comment2Edit)!=null; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteComment(String commentid, String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, CommentIDNotFoundException, FeedIDNotFoundException { + return commentClient.deleteCommentLib(commentid, feedid); + } + /** + * {@inheritDoc} + */ + @Override + public boolean like(Like like) throws FeedIDNotFoundException { + return likeClient.likeLib(like); + } + /** + * {@inheritDoc} + */ + @Override + public boolean unlike(String userid, String likeid, String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, LikeIDNotFoundException, FeedIDNotFoundException { + return likeClient.unlikeLib(userid, likeid, feedid); + } + /** + * {@inheritDoc} + */ + @Override + @Deprecated + public List getAllLikedFeedIdsByUser(String userid) { + return getAllLikedPostIdsByUser(userid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllLikedPostIdsByUser(String userid) { + return likeClient.getAllLikedPostIdsByUserLib(userid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllLikedFeedsByUser(String userid, int limit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + ArrayList toReturn = new ArrayList<>(); + List likedPostIDs = getAllLikedPostIdsByUser(userid); + + //check if quantity is greater than user feeds + limit = (limit > likedPostIDs.size()) ? likedPostIDs.size() : limit; + + //need them in reverse order + for (int i = likedPostIDs.size()-1; i >= (likedPostIDs.size()-limit); i--) { + Feed toAdd = readFeed(likedPostIDs.get(i)); + if (toAdd.getType() == FeedType.TWEET || toAdd.getType() == FeedType.SHARE || toAdd.getType() == FeedType.PUBLISH) { + toReturn.add(toAdd); + _log.trace("Read recent post: " + likedPostIDs.get(i)); + } else { + _log.trace("Read and skipped post: " + likedPostIDs.get(i) + " (Removed post)"); + limit += 1; //increase the quantity in case of removed feed + //check if quantity is greater than user feeds + limit = (limit > likedPostIDs.size()) ? likedPostIDs.size() : limit; + } + } + return toReturn; + } + /** + * {@inheritDoc} + */ + @Override + public List getAllLikedPostsByUser(String userid, int limit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException { + ArrayList toReturn = new ArrayList(); + List likedPostIDs = getAllLikedPostIdsByUser(userid); + + //check if quantity is greater than user feeds + limit = (limit > likedPostIDs.size()) ? likedPostIDs.size() : limit; + + //need them in reverse order + for (int i = likedPostIDs.size()-1; i >= (likedPostIDs.size()-limit); i--) { + Post toAdd = readPost(likedPostIDs.get(i)); + if (toAdd.getType() == PostType.TWEET || toAdd.getType() == PostType.SHARE || toAdd.getType() == PostType.PUBLISH) { + toReturn.add(toAdd); + _log.trace("Read recent post: " + likedPostIDs.get(i)); + } else { + _log.trace("Read and skipped post: " + likedPostIDs.get(i) + " (Removed post)"); + limit += 1; //increase the quantity in case of removed feed + //check if quantity is greater than user feeds + limit = (limit > likedPostIDs.size()) ? likedPostIDs.size() : limit; + } + } + return toReturn; + } + + /** + * {@inheritDoc} + */ + @Override + public List getRecentLikedFeedsByUserAndDate(String userid, + long timeInMillis) throws IllegalArgumentException { + + List toReturn = new ArrayList<>(); + + Date now = new Date(); + if (timeInMillis > now.getTime()) + throw new IllegalArgumentException("the timeInMillis must be before today"); + + if(userid == null || userid.isEmpty()) + throw new IllegalArgumentException("the userId parameter cannot be null/empty"); + + // get the list of liked feeds + List likedPostsIdsByUser = getAllLikedFeedIdsByUser(userid); + + if(likedPostsIdsByUser != null && !likedPostsIdsByUser.isEmpty()){ + for(int i = likedPostsIdsByUser.size() - 1; i >= 0; i--){ + String postid = likedPostsIdsByUser.get(i); + try{ + + // retrieve the Post + Feed toCheck = readFeed(postid); + boolean isPostOk = (toCheck.getType() == FeedType.TWEET || toCheck.getType() == FeedType.SHARE || toCheck.getType() == FeedType.PUBLISH); + + // retrieve the like of the user for the post + if(isPostOk){ + List likes = getAllLikesByFeed(postid); + for (Like like : likes) { + if(like.getTime().getTime() >= timeInMillis && like.getUserid().equals(userid)) + toReturn.add(toCheck); + } + } + + }catch(Exception e){ + _log.error("Skipped post with id " + postid, e); + } + } + } + + // please check consider that if a user made like recently to an old post, well it could happen that this + // post comes first than a newer post in the toReturn list. Thus we need to sort it. + Collections.sort(toReturn, Collections.reverseOrder()); + + return toReturn; + + } + /** + * {@inheritDoc} + */ + @Override + public List getRecentLikedPostsByUserAndDate(String userid, + long timeInMillis) throws IllegalArgumentException { + + List toReturn = new ArrayList<>(); + + Date now = new Date(); + if (timeInMillis > now.getTime()) + throw new IllegalArgumentException("the timeInMillis must be before today"); + + if(userid == null || userid.isEmpty()) + throw new IllegalArgumentException("the userId parameter cannot be null/empty"); + + // get the list of liked feeds + List likedPostsIdsByUser = getAllLikedPostIdsByUser(userid); + + if(likedPostsIdsByUser != null && !likedPostsIdsByUser.isEmpty()){ + for(int i = likedPostsIdsByUser.size() - 1; i >= 0; i--){ + String postid = likedPostsIdsByUser.get(i); + try{ + + // retrieve the Post + Post toCheck = readPost(postid); + boolean isPostOk = (toCheck.getType() == PostType.TWEET || toCheck.getType() == PostType.SHARE || toCheck.getType() == PostType.PUBLISH); + + // retrieve the like of the user for the post + if(isPostOk){ + List likes = getAllLikesByPost(postid); + for (Like like : likes) { + if(like.getTime().getTime() >= timeInMillis && like.getUserid().equals(userid)) + toReturn.add(toCheck); + } + } + + }catch(Exception e){ + _log.error("Skipped post with id " + postid, e); + } + } + } + + // please check consider that if a user made like recently to an old post, well it could happen that this + // post comes first than a newer post in the toReturn list. Thus we need to sort it. + Collections.sort(toReturn, Collections.reverseOrder()); + + return toReturn; + } + + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public List getAllLikesByFeed(String feedid) { + return getAllLikesByPost(feedid); + } + /** + * {@inheritDoc} + */ + @Override + public List getAllLikesByPost(String postid) { + //possible error index + return likeClient.getAllLikesByPostLib(postid); + } + /* + * + ********************** HASHTAGS *********************** + * + */ + /** + * {@inheritDoc} + */ + @Override + public boolean saveHashTags(String feedid, String vreid, List hashtags) throws FeedIDNotFoundException { + return hashTagClient.saveHashTagsLib(feedid, vreid, hashtags); + } + /** + * {@inheritDoc} + */ + @Override + public boolean deleteHashTags(String feedid, String vreid, List hashtags) throws FeedIDNotFoundException { + return hashTagClient.deleteHashTagsLib(feedid, vreid, hashtags); + } + /** + * {@inheritDoc} + */ + @Override + public boolean saveHashTagsComment(String commentId, String vreid, List hashtags) throws CommentIDNotFoundException { + return hashTagClient.saveHashTagsCommentLib(commentId, vreid, hashtags); + } + /** + * {@inheritDoc} + */ + @Override + public boolean deleteHashTagsComment(String commentId, String vreid, List hashtags) throws CommentIDNotFoundException { + return hashTagClient.deleteHashTagsCommentLib(commentId, vreid, hashtags); + } + /** + * {@inheritDoc} + */ + @Override + public Map getVREHashtagsWithOccurrence(String vreid) { + return hashTagClient.getVREHashtagsWithOccurrenceLib(vreid); + } + /** + * {@inheritDoc} + */ + @Override + public Map getVREHashtagsWithOccurrenceFilteredByTime(String vreid, long timestamp){ + return hashTagClient.getVREHashtagsWithOccurrenceFilteredByTimeLib(vreid, timestamp); + } + + /** + * {@inheritDoc} + */ + @Override + public List getVREFeedsByHashtag(String vreid, String hashtag) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + return null; + } + /** + * {@inheritDoc} + */ + @Override + public List getVREPostsByHashtag(String vreid, String hashtag) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + return hashTagClient.getVREPostsByHashtagLib(vreid, hashtag); + } + /* + * + ********************** Invites *********************** + * + */ + + + /** + * {@inheritDoc} + */ + @Override + public String isExistingInvite(String vreid, String email) { + return inviteClient.isExistingInviteLib(vreid, email); + } + /** + * {@inheritDoc} + */ + @Override + public InviteOperationResult saveInvite(Invite invite) throws AddressException { + return inviteClient.saveInviteLib(invite); + } + /** + * {@inheritDoc} + */ + @Override + public Invite readInvite(String inviteid) throws InviteIDNotFoundException, InviteStatusNotFoundException { + return inviteClient.readInviteLib(inviteid); + } + + /** + * {@inheritDoc} + * @throws InviteStatusNotFoundException + */ + @Override + public boolean setInviteStatus(String vreid, String email, InviteStatus status) throws InviteIDNotFoundException, InviteStatusNotFoundException { + return inviteClient.setInviteStatusLib(vreid, email, status); + } + /** + * {@inheritDoc} + */ + @Override + public List getInvitedEmailsByVRE(String vreid, InviteStatus... status) throws InviteIDNotFoundException, InviteStatusNotFoundException{ + return inviteClient.getInvitedEmailsByVRELib(vreid, status); + } + /** + * {@inheritDoc} + */ + @Override + public List getAttachmentsByFeedId(String feedId) throws FeedIDNotFoundException { + return postClient.getAttachmentsByFeedIdLib(feedId); + } + /** + * {@inheritDoc} + */ + @Override + public void closeConnection() { + } + + @Override + public List getAllVREIds(){ + return postClient.getAllVREIdsLib(); + } +} diff --git a/target/classes/org/gcube/portal/databook/server/DatabookCassandraTest.class b/target/classes/org/gcube/portal/databook/server/DatabookCassandraTest.class new file mode 100644 index 0000000000000000000000000000000000000000..e1217da416a677072903a3fdfd213ede418afa66 GIT binary patch literal 973 zcmbVKTWb?R6#gc+?QYhjCT(i!{hn6s`XDMsgfvzVf{G~tA19k>oVb|@yR)VJSypI4 z!5`p{63=d8Vxge;GIOrq`Of9X&#&JBJi res = store.getRecentCommentedFeedsByUserAndDate(userid, oneYearAgo.getTimeInMillis()); + // long end = System.currentTimeMillis(); + // System.out.println("Result is " + (end - init)); + // + // + // } + // @Test + // public void getRecentCommentsByUserAndDate() throws Exception{ + // + // String userid = "costantino.perciante"; + // Calendar oneYearAgo = Calendar.getInstance(); + // oneYearAgo.set(Calendar.YEAR, oneYearAgo.get(Calendar.YEAR) - 1); + // + // List res = store.getRecentCommentsByUserAndDate(userid, oneYearAgo.getTimeInMillis()); + // + // for (Comment comment : res) { + // System.out.println("Result is " + comment); + // } + // + // + // + // + // } + // @Test + // public void getRecentLikedFeedsByUser(){ + // + // String userid = "costantino.perciante"; + // Calendar oneYearAgo = Calendar.getInstance(); + // oneYearAgo.set(Calendar.YEAR, oneYearAgo.get(Calendar.YEAR) - 1); + // + // List result = store.getRecentLikedFeedsByUserAndDate(userid, oneYearAgo.getTimeInMillis()); + // + // for (Feed feed : result) { + // System.out.println("Result is " + feed); + // } + // } + // @Test + // public void getHashTagsFilteredByTime() throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException{ + // + // int windowSize = 6; // go back windowSize months + // + // String vreUnderTest = "/gcube/devsec/devVRE"; + // + // // reference time + // Calendar calendar = Calendar.getInstance(); + // int currentMonth = calendar.get(Calendar.MONTH); // jan = 0, ..... dec = 11 + // calendar.set(Calendar.MONTH, currentMonth - windowSize); // the year is automatically decreased if needed + // SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + // System.out.println("Reference time for trending topics is " + format.format(calendar.getTime())); + // + // Map res = + // store.getVREHashtagsWithOccurrenceFilteredByTime( + // vreUnderTest, calendar.getTimeInMillis()); + // + // // find max score inside the list (counter) + // int max = 0; + // for(Entry entry : res.entrySet()){ + // + // max = max < entry.getValue() ? entry.getValue() : max; + // + // } + // + // // normalize + // Map normalized = new HashMap(); + // for(Entry entry : res.entrySet()){ + // + // normalized.put(entry.getKey(), (double)entry.getValue() / (double)max); + // + // } + // + // // create the weight for each entry as: + // // w = 0.6 * normalized_score + 0.4 * freshness + // // freshness is evaluated as (window_size - latest_feed_for_hashtag_in_window_month)/window_size + // Map scoredList = new HashMap(); + // for(Entry entry : res.entrySet()){ + // + // double weight = 0.6 * normalized.get(entry.getKey()); + // + // // retrieve the last feed for this hashtag and locate it into the window + // List mostRecentFeedForHashtag = store.getVREFeedsByHashtag(vreUnderTest, entry.getKey()); + // + // // retrieve the most recent one among these feeds + // Collections.sort(mostRecentFeedForHashtag, Collections.reverseOrder()); + // + // // locate into the window + // Calendar locateInWindow = Calendar.getInstance(); + // locateInWindow.setTimeInMillis(mostRecentFeedForHashtag.get(0).getTime().getTime()); + // + // // get the month + // int sub = currentMonth - locateInWindow.get(Calendar.MONTH); + // int value = sub >= 0? sub : 12 - Math.abs(sub); + // double freshness = (double)(windowSize - value) / (double)(windowSize); + // System.out.println("freshness is " + freshness + " because the last feed has month " + locateInWindow.get(Calendar.MONTH)); + // + // weight += 0.4 * freshness; + // + // scoredList.put(entry.getKey(), weight); + // } + // + // // print sorted + // Map scoredListSorted = sortByValue(scoredList); + // for(Entry entry : scoredListSorted.entrySet()){ + // + // System.out.println("[hashtag=" + entry.getKey() + " , weight=" + entry.getValue() + "]"); + // } + // } + // + // public static > Map + // sortByValue( Map map ) + // { + // List> list = + // new LinkedList>( map.entrySet() ); + // Collections.sort( list, new Comparator>() + // { + // public int compare( Map.Entry o1, Map.Entry o2 ) + // { + // return (o2.getValue()).compareTo( o1.getValue() ); + // } + // }); + // + // Map result = new LinkedHashMap(); + // for (Map.Entry entry : list) + // { + // result.put( entry.getKey(), entry.getValue() ); + // } + // return result; + // } + + + // @Test + // public void getHashTags() throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException{ + // List resList = store.getVREFeedsByHashtag("/gcube/devsec/devVRE", "#test"); + // + // for (Feed feed : resList) { + // System.out.println(feed.getTime()); + // } + // + // } + + // @Test + // public void getComment(){ + // + // String uuid = "820969b2-4632-4197-9fd6-5aafab781faa"; + // + // Comment c; + // try { + // c = store.readCommentById(uuid); + // System.err.println(c); + // } catch (CommentIDNotFoundException e) { + // // TODO Auto-generated catch block + // System.err.println(e.toString()); + // } + // } + + // @Test + // public void vreIds(){ + // + // try { + // List ids = store.getAllVREIds(); + // System.out.println(ids); + // } catch (ConnectionException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // + // } + + // @Test + // public void testFeedNumberPerUser() { + // String userid = "massimiliano.assante"; + // + // List feeds = null; + // int numComment = 0; + // long init = System.currentTimeMillis(); + // try { + // feeds = store.getAllFeedsByUser(userid); + // + // for (Feed feed : feeds) { + // List comments = store.getAllCommentByFeed(feed.getKey()); + // + // + // for (Comment comment : comments) { + // numComment ++; + // } + // } + // + // } catch (PrivacyLevelTypeNotFoundException | FeedTypeNotFoundException + // | ColumnNameNotFoundException | FeedIDNotFoundException e) { + // // TODO Auto-generated catch block + // System.err.println(e.toString()); + // } + // long end = System.currentTimeMillis(); + // System.err.println("retrieved " + feeds.size() + " and " + numComment + " in " + (end - init) + "ms"); + // } + + // @Test + // public void testAttachments() { + // Attachment a1 = new Attachment(UUID.randomUUID().toString(), "www1", "gattino1", "description1", "http://cdn.tuttozampe.com/wp-content/uploads/2010/09/ipoglicemia-gatto.jpg", "image/jpg"); + // Attachment a2 = new Attachment(UUID.randomUUID().toString(), "www2", "name2", "description2", "http://www.gcomegatto.it/wp-content/uploads/2015/01/09gatto.jpg","image/jpg"); + // Attachment a3 = new Attachment(UUID.randomUUID().toString(), "www3", "name3", "description3", "http://cdn.tuttozampe.com/wp-content/uploads/2010/09/ipoglicemia-gatto.jpg","image/jpg"); + // List toPass = new ArrayList(); + // toPass.add(a1); + // toPass.add(a2); + // toPass.add(a3); + // + // String feedId = UUID.randomUUID().toString(); + // Feed feed = new Feed(feedId, FeedType.TWEET, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "http://www.dailybest.it/wp-content/uploads/2015/10/gattini-nele-ciotole-e1344352237289.jpg", + // "http://www.dailybest.it/wp-content/uploads/2015/10/gattini-nele-ciotole-e1344352237289.jpg", + // "This post has attachments (gattini) ", PrivacyLevel.SINGLE_VRE, + // "Massimiliano Assante", + // "massimiliano.assante@isti.cnr.it", + // "http://www.dailybest.it/wp-content/uploads/2015/10/gattini-nele-ciotole-e1344352237289.jpg", + // "Gattino", + // "linkDesc", + // "image/jpeg", false); + // feed.setMultiFileUpload(true); + // assertTrue(store.saveUserFeed(feed, toPass)); + // System.out.println("Wrote post? "); + // System.out.println("Feed has the following attachments: "); + // try { + // for (Attachment at : store.getAttachmentsByFeedId(feedId)) { + // System.out.println(at); + // } + // } catch (FeedIDNotFoundException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // + // } + + // @Test + // public void testHashTag() { + // try { + // final String VREID = "/gcube/devsec/devVRE"; + // final String HASHTAG1 = "#testHashTag"; + // final String HASHTAG2 = "#testHashTag3"; + // List hashtags = new LinkedList(); + // hashtags.add(HASHTAG1); + // hashtags.add(HASHTAG2); + // + //// Feed feed = new Feed(UUID.randomUUID().toString(), FeedType.TWEET, "massimiliano.assante", new Date(), VREID, + //// "www.d4science.org/monitor", "thumbUri", "This is a feed with " + HASHTAG1 + " and " + HASHTAG2, PrivacyLevel.VRES, "Massimiliano Assante", "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host"); + //// assertTrue(store.saveUserFeed(feed)); + //// assertTrue(store.saveHashTags(feed.getKey(), VREID, hashtags)); + //// assertTrue(store.deleteHashTags("d0c64e42-9616-4e24-a65a-7a63a280d676", VREID, hashtags)); + //// System.out.println(feed); + //// + // System.out.println("\ngetting getVREHashtagsWithOccurrence for " + VREID); + // Map hashtagsWithOcc = store.getVREHashtagsWithOccurrence(VREID); + // for (String hashtag : hashtagsWithOcc.keySet()) { + // System.out.println(hashtag + ":" + hashtagsWithOcc.get(hashtag)); + // } + // + // System.out.println("\ngetting getVREFeedsByHashtag for " + VREID + " and " + HASHTAG1); + // for (Feed theFeed : store.getVREFeedsByHashtag(VREID, HASHTAG1)) { + // System.out.println(theFeed); + // } + // + // } catch (Exception e) { + // e.printStackTrace(); + // } + // + // + // } + + +// /** +// * use exclusively to add a new (Static) CF to a keyspace with a secondary index +// */ +// @Test +// public void addAttachmentStaticColumnFamilies() { +// ColumnFamily CF_ATTACHMENTS = ColumnFamily.newColumnFamily(DBCassandraAstyanaxImpl.ATTACHMENTS, StringSerializer.get(), StringSerializer.get()); +// +// try { +// String colNameToIndex = "feedId"; +// new CassandraClusterConnection(false).getKeyspace().createColumnFamily(CF_ATTACHMENTS, ImmutableMap.builder() +// .put("column_metadata", ImmutableMap.builder() +// .put(colNameToIndex, ImmutableMap.builder() +// .put("validation_class", "UTF8Type") +// .put("index_name", "FeedIndex_"+UUID.randomUUID().toString().substring(0,5)) +// .put("index_type", "KEYS") +// .build()) +// .build()) +// .build()); +// +// +// } catch (ConnectionException e) { +// e.printStackTrace(); +// } +// System.out.println("addStaticColumnFamily END"); +// } +// + +// /** +// * use exclusively to add a new (Dynamic) CF to a keyspace +// */ +// @Test +// public void addInvitesDynamicColumnFamilies() { +// System.out.println("UserNotificationsUnread"); +// ColumnFamily cf_UserNotificationsUnreadTimeline = new ColumnFamily( +// DBCassandraAstyanaxImpl.EMAIL_INVITES, // Column Family Name +// StringSerializer.get(), // Key Serializer +// StringSerializer.get()); // Column Serializer +// +// try { +// +// new CassandraClusterConnection(false).getKeyspace().createColumnFamily(cf_UserNotificationsUnreadTimeline, ImmutableMap.builder() +// .put("default_validation_class", "UTF8Type") +// .put("key_validation_class", "UTF8Type") +// .put("comparator_type", "UTF8Type") +// .build()); +// +// } catch (ConnectionException e) { +// e.printStackTrace(); +// } +// System.out.println("UserNotificationsUnread END"); +// } + + + // private List getKeys() { + // List toReturn = new ArrayList(); + // try { + // + // OperationResult> rows = store.getConnection().getKeyspace().prepareQuery(DBCassandraAstyanaxImpl.cf_UserNotificationsPreferences) + // .getAllRows() + // .setRowLimit(1000) // This is the page size + // .execute(); + // int i = 1; + // for (Row row : rows.getResult()) { + // System.out.println(i+" ROW: " + row.getKey() + " " + row.getColumns().size()); + // toReturn.add(row.getKey()); + // i++; + // } + // } catch (ConnectionException e) { + // e.printStackTrace(); + // } + // return toReturn; + // } + // + // @Test + // public void testUserNotificationPreferences() { + // System.out.println("Notification type" + NotificationType.POST_ALERT.toString() +" OFF for:"); + // try { + // for (String user : getKeys()) { + // List channels = store.getUserNotificationChannels(user, NotificationType.POST_ALERT); + // if (channels.isEmpty()) { + // System.out.println(user); + // } + // else if (! channels.contains(NotificationChannelType.EMAIL)) { + // System.out.println(user + "->" + channels.toString()); + // } + // } + + + // for (NotificationChannelType channel : store.getUserNotificationChannels("roberto.trasarti", NotificationType.POST_ALERT)) { + // System.out.println(channel); + // } + // } catch (NotificationChannelTypeNotFoundException e) { + // e.printStackTrace(); + // } catch (NotificationTypeNotFoundException e) { + // e.printStackTrace(); + // }; + // + // } + + // @Test + // public void testLikes() { + // int count = 10; + // Feed feed = new Feed(UUID.randomUUID().toString(), FeedType.SHARE, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "http://www.d4science.org/monitor", "thumbUri", "This feed is Liked ", PrivacyLevel.PUBLIC, + // "Massimiliano Assante", "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host", false); + // assertTrue(store.saveUserFeed(feed)); + // Like toUnlike = new Like(UUID.randomUUID().toString(),"massimiliano.assante", + // new Date(), feed.getKey().toString(), "Massi Pallino", "thumbUrl"); + // + // try { + // assertTrue(store.like(toUnlike)); + // for (int i = 0; i < count; i++) + // assertTrue(store.like(new Like(UUID.randomUUID().toString(),"massimiliano.assante", + // new Date(), feed.getKey().toString(), "Rino Pallino", "thumbUrl"))); + // + // System.out.println("massimiliano.assante liked the following feeds: "); + // for (String feedid : store.getAllLikedFeedIdsByUser("massimiliano.assante")) { + // System.out.println(feedid); + // } + // + // for (Like like : store.getAllLikesByFeed(feed.getKey().toString())) { + // System.out.println(like); + // } + // System.out.println("massimiliano.assante trying unlike the following feed: " + toUnlike); + // store.unlike("massimiliano.assante", toUnlike.getKey(), toUnlike.getFeedid()); + // + // } catch (Exception e) { + // System.out.println("Exception feed id not found"); + // } + // } + // /** + // * use exclusively to add a new CF to a keyspace + // */ + // @Test + // public void addNotifPreferencesColumnFamily() { + // // ColumnFamily cf_UserNotificationsPreferences = new ColumnFamily( + // // DBCassandraAstyanaxImpl.USER_NOTIFICATIONS_PREFERENCES, // Column Family Name + // // StringSerializer.get(), // Key Serializer + // // StringSerializer.get()); // Column Serializer + // // + // // try { + // // new CassandraClusterConnection(false).getKeyspace().createColumnFamily(cf_UserNotificationsPreferences, ImmutableMap.builder() + // // .put("default_validation_class", "UTF8Type") + // // .put("key_validation_class", "UTF8Type") + // // .put("comparator_type", "UTF8Type") + // // .build()); + // // } catch (ConnectionException e) { + // // e.printStackTrace(); + // // } + // } + // + // @Test + // public void testFriendships() { + // assertTrue(store.requestFriendship("massimiliano.assante", "leonardo.candela")); + // assertTrue(store.requestFriendship("massimiliano.assante", "ermit")); + // assertTrue(store.requestFriendship("massimiliano.assante", "giorgino")); + // assertTrue(store.requestFriendship("barabba", "massimiliano.assante")); + // + // assertTrue(store.approveFriendship("leonardo.candela", "massimiliano.assante")); + // assertTrue(store.approveFriendship("ermit", "massimiliano.assante")); + // + // assertTrue(store.denyFriendship("giorgino", "massimiliano.assante")); + // System.out.println("Pending Connections for massimiliano.assante:"); + // for (String userid: store.getPendingFriendRequests("massimiliano.assante")) { + // System.out.println(userid); + // } + // + // System.out.println("Connections for massimiliano.assante:"); + // for (String userid: store.getFriends("massimiliano.assante")) { + // System.out.println(userid); + // } + // + // } + // @Test + // public void testLikedFeedsRetrieval() { + // try { + // for (Feed feed : store.getAllLikedFeedsByUser("luca.frosini", 10)) { + // System.out.println(feed); + // } + // } catch (Exception e) { + // e.printStackTrace(); + // } + // } + // + // + // + // + // @Test + // public void testSingleNotification() { + // Notification not = new Notification( + // UUID.randomUUID().toString(), + // NotificationType.LIKE, + // "leonardo.candela", + // "MESSAGEID", + // new Date(), + // "uri", + // "This is notification about a like", + // false, + // "leonardo.candela", "Leonardo Candela", + // "thumburl"); + // assertTrue(store.saveNotification(not)); + // + // not = new Notification( + // UUID.randomUUID().toString(), + // NotificationType.MESSAGE, + // "massimiliano.assante", + // "MESSAGEID", + // new Date(), + // "uri", + // "This is notification about a like", + // false, + // "antonio.gioia", "Antonio Gioia", + // "thumburl"); + // assertTrue(store.saveNotification(not)); + // System.out.println("Writing one Notification " + not); + // } + // + // @Test + // public void testNotifications() { + // Notification not = null; + // System.out.println("Writing 18 Notifications"); + // int count = 18; + // for (int i = 0; i < count; i++) { + // if (i % 2 != 0) { + // not = new Notification(UUID.randomUUID().toString(), NotificationType.JOB_COMPLETED_OK, + // "leonardo.candela", "TWEETID", new Date(), "uri", "This is notification about job completed OK #"+i, false, "pasquale.pagano", "Pasquale Pagano", "thumburl"); + // } else { + // not = new Notification(UUID.randomUUID().toString(), NotificationType.JOB_COMPLETED_NOK, + // "massimiliano.assante", "MESSAGEID", new Date(), "uri", "This is notification about completed NOK #"+i, false, "leonardo.candela", "Leonardo Candela", "thumburl"); + // } + // assertTrue(store.saveNotification(not)); + // try { + // Thread.sleep(150); + // } catch (InterruptedException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // } + // + // Notification rNot= null; + // try { + // + // //read + // rNot = store.readNotification(not.getKey().toString()); + // assertNotNull(rNot); + // System.out.println("Reading one Notification " + rNot.getKey() + ": " + rNot.getDescription() + " Type: " + rNot.getType()); + // + // //set Read + // assertTrue(store.setNotificationRead(rNot.getKey().toString())); + // + // System.out.println("Notification " + rNot.getKey() + " of Type: " + rNot.getType() + " was set to READ"); + // + // not = new Notification(UUID.randomUUID().toString(), NotificationType.LIKE, + // "leonardo.candela", "FEEDID", new Date(), "uri", "This is notification of a Liked Leo feed by Massi", false, "massimiliano.assante", "Massimiliano Assante", "thumburl"); + // assertTrue(store.saveNotification(not)); + // try { + // Thread.sleep(150); + // } catch (InterruptedException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // rNot = store.readNotification(not.getKey().toString()); + // System.out.println("Reading another Notification " + rNot.getKey() + " of Type: " + rNot.getType() + " Read:? " + rNot.isRead()); + // // //set Read + // // assertTrue(store.setNotificationRead(rNot.getKey().toString())); + // // System.out.println("Notification " + rNot.getKey() + " of Type: " + rNot.getType() + " was set to READ subject was this: " + rNot.getSubjectid()); + // // + // Random randomGenerator = new Random(); + // + // System.out.println("leonardo.candela Notifications: "); + // List recentNots = store.getAllNotificationByUser("leonardo.candela", randomGenerator.nextInt(50)); + // assertNotNull(recentNots); + // for (Notification notif :recentNots) + // System.out.println(notif); + // + // + // System.out.println("massimiliano.assante Notifications: "); + // recentNots = store.getUnreadNotificationsByUser("massimiliano.assante"); + // assertNotNull(recentNots); + // for (Notification notif :recentNots) + // System.out.println(notif); + // } catch (Exception e) { + // e.printStackTrace(); + // } + // + // System.out.println("getRangeNotificationsByUser massimiliano.assante: "); + // try { + // int from = 0; + // for (int i = 0; i < 5; i++) { + // System.out.println("\nFROM="+from); + // List range = store.getRangeNotificationsByUser("massimiliano.assante", from, 50); + // for (Notification notification : range) { + // System.out.println(notification.getDescription()); + // from = 1+i * 50; + // } + // } + // } catch (Exception e) { + // e.printStackTrace(); + // } + // } + // + // + // @Test + // public void testFeeds() { + // int count = 18; + // Feed feed = null; + // for (int i = 0; i < count; i++) { + // if (i % 2 != 0) { + // feed = new Feed(UUID.randomUUID().toString(), FeedType.JOIN, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "www.d4science.org/monitor", "thumbUri", "This is feed# "+ i, PrivacyLevel.VRES, "Massimiliano Assante", "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host"); + // } else { + // feed = new Feed(UUID.randomUUID().toString(), FeedType.TWEET, "leonardo.candela", new Date(), "", + // "www.d4science.org/web/guest", "thumbUri", "This is feed# "+ i, PrivacyLevel.PORTAL, "Leonardo Candela", "leonardo.candela@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host"); + // } + // assertTrue(store.saveUserFeed(feed)); + // try { + // Thread.sleep(150); + // } catch (InterruptedException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // } + // + // Feed rFeed = null; + // try { + // rFeed = store.readFeed(feed.getKey().toString()); + // rFeed = store.readFeed(feed.getKey().toString()); + // rFeed = store.readFeed(feed.getKey().toString()); + // rFeed = store.readFeed(feed.getKey().toString()); + // assertNotNull(rFeed); + // + // String feedIdToDelete = UUID.randomUUID().toString(); + // feed = new Feed(feedIdToDelete, FeedType.PUBLISH, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "www.d4science.org/monitor", "thumbUri", "This is feed to be deleted", PrivacyLevel.VRES, "Massimiliano Assante", "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host", false); + // assertTrue(store.saveUserFeed(feed)); + // try { + // Thread.sleep(250); + // } catch (InterruptedException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // System.out.println("Test Delete Feed "); + // assertTrue(store.deleteFeed(feedIdToDelete)); + // + // System.out.println("massimiliano.assante ALL FEEDS: "); + // for (Feed recFeed : store.getAllFeedsByUser("massimiliano.assante")) + // System.out.println(recFeed); + // } + // catch (Exception e) { + // e.printStackTrace(); + // } + // } + // + // + // + // @Test + // public void testComments() { + // int count = 10; + // Feed feed = new Feed(UUID.randomUUID().toString(), FeedType.SHARE, "massimiliano.assante", new Date(), "/gcube/devsec/devVRE", + // "http://www.d4science.org/monitor", "thumbUri", "This is feed that is going to be commented ", PrivacyLevel.PUBLIC, "Massimiliano Assante", + // "massimiliano.assante@isti.cnr.it", "thumburl", "linkTitle", "linkDesc", "host", false); + // assertTrue(store.saveUserFeed(feed)); + // + // Comment toDelete = null; + // for (int i = 0; i < count; i++) { + // try { + // toDelete = new Comment(UUID.randomUUID().toString(),"leonardo.candela", + // new Date(), feed.getKey().toString(), "This comment #"+i, "Leonardo Candela", "thumbUrl"); + // assertTrue(store.addComment(toDelete)); + // + // } catch (FeedIDNotFoundException e) { + // System.out.println("Exception feed id not found"); + // } + // } + // System.out.println("GetAllCOmmentsByFeed "); + // for (Comment cm : store.getAllCommentByFeed(feed.getKey().toString())) { + // try { + // System.out.println(store.readCommentById(cm.getKey())); + // } catch (CommentIDNotFoundException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // }; + // + // try { + // assertTrue(store.deleteComment(toDelete.getKey(), toDelete.getFeedid())); + // } catch (Exception e) { + // System.out.println("Exception feed id not found"); + // } + // } + + +} diff --git a/target/classes/org/gcube/portal/databook/server/DatabookStore.class b/target/classes/org/gcube/portal/databook/server/DatabookStore.class new file mode 100644 index 0000000000000000000000000000000000000000..f23844b75dc4dedd3b9eceb89a4aa1029798e249 GIT binary patch literal 9103 zcmcgxX?qmM5v~S>#R7u>;}DFAVgr^)%qF(uOMoMUWG@yVO9B#{#2I#*)xc_YJv*zQ zT()y3b`HnRec$)>H6QW=@}u(Pt?r)Qo|(ow+DFb8>6xzTs<-a$-v9jfU;ieeN9dmw z+9K#gJ8o8+_1-mE?X=@0XjL0Q5?pJyZ&tf9UXyY4todF_+Oe$Ah@i0>!CFvl1yQql z@!AbpPXz6W<%>PpP3GcIMvd-D*b(%=#C)G|DT%|VIaOSlyo%jHrxUl=q`P}pLq_ZF z!e~>b;sqV?$ez@~dr8=;&WGJ(O3)okVKWMnUMvMYUSiA1BEHiQa{#IrU>7XVh!(ZA zT|qm$!J51TSItS;5OjQE{w*B362!7mWzH!!d-SaA#IhbFyweI=Xm{bzGJ=>>33{@u z*1U%pML6WU3$K%Bo?3`Zf;(bhIH`GLbr{`+b?i@teI>mz^YR zN8JkDBWP-1=;bXH{o2_J?PRXqiyBr!h3*wJTSmY_9IgfR^?A7_Tg&Sm=@IpAL8r=y zV)Jez;yr?%DkEa1-RiAI7lPFy4me1AQD^jit`w!QeR*+qIb4;kFhX6bb!J)4uJ2&} z=}t$-ApO#^w#PDPXu^~)ID=D@H>0wZAT4u9LA)7)_Mk;fw^}T=duE**f}rzWXsRdL zCRHLi6;y6RMh9!$Y#qu9)-jf`1Mas=My*;p0Smah-Bv@h=+ ztX61F(0%0oV~dh`k4GjFb`i%gl-i7^QfjbtU=LUORSZ%6 zeI0$xo25fZ%;<13$5vhe0k=|19pjmRffrs6acsii74%Svv7_vmPi>)CA?8Xc#$f;+LSE#Y!l{uu<`8^#DauF08gR*jYct$-puQsO zH$934jXR|CvfB-svYT4ZGn>ke>+-U|2%2kuW zb(>mv!{gtG8pqee!<_TE^vRfazX!LQ4s4$wU+i*R|9A5Q?dDoGN7ys#HKgomuQdaw zf{}r=Z$rjFcBH-8;h7(}HwBFpm7oVp47gN12aHb-=wa3>p0a`#yms}|iyur%1Rzz! z-8`>|2fWUg%+(-&DR|CzUJ3Vp8Rn*eL|CW0B#Ojj4ITK{tClGyVO>293?c9$JcF2Nk|xU?}w zutNtezsVlGaxBhv%VO@QECMQZ-fhwym}RPNo7JIHPCcDH6LeRWgC_dzV;hK=y@#uy zKRe7$@0+12L_Vyhuxv8oU6Wsy(sjIlWEU(WA2x9CXT}6}T?vzwi}iXhR%1obIS!xJ zXSjiLOLJcA$XMOJ7G<~BN-*?(jI7{XyH#Bc@cJGiwc9Pp&UCD|*DjPtpShc+Us4K0iG0U+-<5sT?%N}QzI7_;yiNFdnNxi7Tk=55H;xjjGQWA?XC3$#r!n{x16t5A&y!xEN%P@qcfHl_ z%9%E0L zbg)g*aR-~BLgRa3$ySRwv&;D5ec*Z!Tz$J!F74wJpjS&tdH(<@AE1W}7WT)(nP_|v zS{?kjB3v^Lc(}Jx8_VshLMB~_Zi7p#`?&=k51+Rh={Mv#K zW6wwEsuMMr`aGx~_3HVU^>1F{$Fb)H@19S1R|C3cv~va5flecnkaL}yuttBc;5(!n z4(}4UHSH#7Em}2}b7n_a>ClVL3VS_PsND|K#cG1pR11IiGQLl1U=5T{T8W$uT%+R@ zsd(P9eI`#?r%&Zje40LER{Ff3RZ?Cm;N$N4vV)JmU$ME%9Ww0{u2oz|pSLl0xwOBy zj=nG;1HYK@f}4R~Dxmx_*2x{mGHM)P;U^*wN9yAE?{%-;w72lPWHia)~2Pw1zr z4u3{JHx$m_U(l~W`wjgzxAqGCj(+dtF8GY}KY;&_%A-8DatabookStore is the high level interface for querying and adding data to DatabookStore + */ +public interface DatabookStore { + /** + * userid from requests a friendship to userid to + * @return true if everything went fine + */ + boolean requestFriendship(String from, String to); + /** + * userid from approves a friendship to userid to + * @return true if everything went fine + */ + boolean approveFriendship(String from, String to); + /** + * userid from denies a friendship to userid to + * @return true if everything went fine + */ + boolean denyFriendship(String from, String to); + /** + * @param userid the user id you want to know friends + * @return a List of userid representing the friends for the given userid + */ + List getFriends(String userid); + /** + * @param userid the user id you want to know the pending friend requests + * @return a List of userid representing the friends for the given userid + */ + List getPendingFriendRequests(String userid); + /** + * @deprecated use saveUserPost + * save a Feed instance in the store + * @return true if everything went fine + */ + boolean saveUserFeed(Feed feed); + /** + * save a Post instance in the store + * @return true if everything went fine + */ + boolean saveUserPost(Post feed); + /** + * Save a Feed instance in the store having more than one attachment + * Use this if you need to attach more than one file to the post + * + * @deprecated use saveUserPost + * @param attachments a list of attachments starting from the second + * @return true if everything went fine + */ + boolean saveUserFeed(Feed feed, List attachments); + /** + * Save a Post instance in the store having more than one attachment + * Use this if you need to attach more than one file to the post + * + * @param attachments a list of attachments starting from the second + * @return true if everything went fine + */ + boolean saveUserPost(Post post, List attachments); + /** + * Delete a Feed from the store + * @deprecated use saveUserPost + * @throws FeedIDNotFoundException + * @return true if everything went fine + */ + boolean deleteFeed(String feedid) throws FeedIDNotFoundException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException; + /** + * delete a Feed from the store + * @throws FeedIDNotFoundException + * @return true if everything went fine + */ + boolean deletePost(String postid) throws FeedIDNotFoundException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException; + /** + * Save a post in the VRES TimeLine in the store + * @deprecated use savePostToVRETimeline + * @param feedKey feedKey + * @param vreid vre identifier + * @throws FeedIDNotFoundException + */ + boolean saveFeedToVRETimeline(String feedKey, String vreid) throws FeedIDNotFoundException; + /** + * save a post in the VRES TimeLine in the store + * @param postKey the post id + * @param vreid vre identifier + * @throws FeedIDNotFoundException + */ + boolean savePostToVRETimeline(String postKey, String vreid) throws FeedIDNotFoundException; + /** + * @deprecated use saveAppPost + * save a Post instance in the store + * @return true if everything went fine + */ + boolean saveAppFeed(Feed feed); + /** + * save a Post instance in the store + * @return true if everything went fine + */ + boolean saveAppPost(Post feed); + /** + * @deprecated use saveAppPost + * Save a Post instance in the store + * Use this if your app needs to attach more than one file to the post + * + * @param attachments a list of attachments starting from the second + * @return true if everything went fine + */ + boolean saveAppFeed(Feed feed, List attachments); + /** + * Save a Post instance in the store + * Use this if your app needs to attach more than one file to the post + * + * @param attachments a list of attachments starting from the second + * @return true if everything went fine + */ + boolean saveAppPost(Post feed, List attachments); + /** + * @deprecated use readPost + * read a feed from a given id + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + Feed readFeed(String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * read a feed from a given id + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + Post readPost(String postid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @deprecated use getAllPostsByUser instead + * @param userid user identifier + * return all the feeds belonging to the userid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllFeedsByUser(String userid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @param userid user identifier + * return all the feeds belonging to the userid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllPostsByUser(String userid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @deprecated use getAllPostsByApp instead + * @param appid application identifier + * return all the feeds belonging to the appid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllFeedsByApp(String appid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @param appid application identifier + * return all the feeds belonging to the appid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllPostsByApp(String appid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * @deprecated use getRecentCommentedPostsByUserAndDate instead + * @param userid the user identifier like andrea.rossi + * @param timeInMillis the initial time in millis to be considered + * @return a list of feeds commented by userid starting from timeInMillis + * @throws Exception + */ + List getRecentCommentedFeedsByUserAndDate(String userid, long timeInMillis) throws Exception; + /** + * @param userid the user identifier like andrea.rossi + * @param timeInMillis the initial time in millis to be considered + * @return a list of feeds commented by userid starting from timeInMillis + * @throws Exception + */ + List getRecentCommentedPostsByUserAndDate(String userid, long timeInMillis) throws Exception; + /** + * @deprecated use getAllPortalPrivacyLevelPosts instead + * return all the feeds whose Level is PORTAL + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + * @throws PrivacyLevelTypeNotFoundException + */ + List getAllPortalPrivacyLevelFeeds() throws FeedTypeNotFoundException, ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException; + /** + * return all the feeds whose Level is PORTAL + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + * @throws PrivacyLevelTypeNotFoundException + */ + List getAllPortalPrivacyLevelPosts() throws FeedTypeNotFoundException, ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException; + + /** + * return the most recent feeds for this user up to quantity param + * @deprecated + * @param userid user identifier + * @param quantity the number of most recent feeds for this user + * @return a List of most recent feeds for this user + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getRecentFeedsByUser(String userid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * return the most recent feeds for this user up to quantity param + * @param userid user identifier + * @param quantity the number of most recent feeds for this user + * @return a List of most recent feeds for this user + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getRecentPostsByUser(String userid, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * @deprecated use getAllPostsByVRE + * @param vreid vre identifier + * return all the feeds belonging to the userid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllFeedsByVRE(String vreid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * @param vreid vre identifier + * return all the feeds belonging to the userid + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllPostsByVRE(String vreid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + + /** + * @deprecated use getRecentPostsByVRE + * return the most recent feeds for this vre up to quantity param + * @param vreid VRES identifier + * @param quantity the number of most recent feeds for this vre + * @return a List of most recent feeds for this vre + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getRecentFeedsByVRE(String vreid, int quantity) throws IllegalArgumentException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * return the most recent posts for this vre up to quantity param + * @param vreid VRES identifier + * @param quantity the number of most recent posts for this vre + * @return a List of most recent posts for this vre + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getRecentPostsByVRE(String vreid, int quantity) throws IllegalArgumentException, PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + + /** + * return the most recent posts for this vre up to quantity param and the last index of the feeds in the timeline + * lastReturnedFeedTimelineIndex is usuful to know from where to start the range the second time you ask + * because there are deletions + * + * @deprecated use getRecentPostsByVREAndRange + * @param vreid VRES identifier + * @param from the range start (most recent feeds for this vre) has to be greater than 0 + * @param quantity the number of most recent feeds for this vre starting from "from" param + * @return a lastReturnedFeedTimelineIndex containing of most recent feeds for this vre + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + RangeFeeds getRecentFeedsByVREAndRange(String vreid, int from, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + /** + * return the most recent posts for this vre up to quantity param and the last index of the posts in the timeline + * lastReturnedPostTimelineIndex is useful to know from where to start the range the next time you ask, because there are deletions + * + * @param vreid VRES identifier + * @param from the range start (most recent feeds for this vre) has to be greater than 0 + * @param quantity the number of most recent feeds for this vre starting from "from" param + * @return a RangePosts containing of most recent feeds for this vre + * @throws FeedTypeNotFoundException + * @throws PrivacyLevelTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + RangePosts getRecentPostsByVREAndRange(String vreid, int from, int quantity) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, FeedIDNotFoundException; + + /** + * @deprecated use getRecentPostsByUserAndDate + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return the number of feeds in the range from: today to: timeInMillis + */ + List getRecentFeedsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException; + /** + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return the number of feeds in the range from: today to: timeInMillis + */ + List getRecentPostsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException; + /** + * save a Notification instance in the store + * @return true if everything went fine + */ + boolean saveNotification(Notification notification); + /** + * set an existing Notification instance in the to read + * @return true if everything went fine + */ + boolean setNotificationRead(String notificationidToSet) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + /** + * read a notification from a given id + * @throws {@link ColumnNameNotFoundException} + * @throws {@link NotificationIDNotFoundException} + * @throws {@link NotificationTypeNotFoundException} + */ + Notification readNotification(String notificationid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + + /** + * @param userid user identifier + * @param limit set 0 to get everything, an int to get the most recent -limit- notifications + * return all the notifications belonging to the userid up to limit, set 0 to get everything + * @throws NotificationTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getAllNotificationByUser(String userid, int limit) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException; + /** + * + * @param userid user identifier + * @param from the range start has to be greater than 0 + * @param quantity the number of most recent notifications for this user starting from "from" param + * @return all the notifications for the userid in the range requested + * @throws NotificationTypeNotFoundException + * @throws ColumnNameNotFoundException + * @throws NotificationIDNotFoundException + */ + List getRangeNotificationsByUser(String userid, int from, int quantity) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException; + /** + * This is a fast way to set all notification to read quickly + * @param userid + * @return true if everything went fine + * @throws {@link ColumnNameNotFoundException} + * @throws {@link NotificationIDNotFoundException} + * @throws {@link NotificationTypeNotFoundException} + */ + boolean setAllNotificationReadByUser(String userid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + /** + * return the not yet read notifications (not including messages) + * @param userid user identifier + * @return a List of not yet read notifications for this user + * @throws NotificationTypeNotFoundException + * @throws ColumnNameNotFoundException + */ + List getUnreadNotificationsByUser(String userid) throws NotificationTypeNotFoundException, ColumnNameNotFoundException, NotificationIDNotFoundException; + /** + * + * @param userid user identifier + * @throws ColumnNameNotFoundException + * @throws NotificationTypeNotFoundException + * @throws NotificationIDNotFoundException + * @return true if there are unread notifications (not including messages), false if they are all read + */ + boolean checkUnreadNotifications(String userid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + /** + * + * @param userid user identifier + * @throws ColumnNameNotFoundException + * @throws NotificationTypeNotFoundException self explaining + * @throws NotificationChannelTypeNotFoundException self explaining + * @throws NotificationIDNotFoundException + * @return true if there are unread messages notifications (including messages), false if they are all read + */ + boolean checkUnreadMessagesNotifications(String userid) throws NotificationIDNotFoundException, NotificationTypeNotFoundException, ColumnNameNotFoundException; + + /** + * return the channels a user chose for being notified for a given notification type + * @param userid user identifier + * @param notificationType the type of the notification + * @return a list of NotificationChannelType that represents the channels this user wants to be notified + */ + List getUserNotificationChannels(String userid, NotificationType notificationType) throws NotificationChannelTypeNotFoundException, NotificationTypeNotFoundException; + /** + * set the notification preferences map (enable or disable the channels to be used for notifying the user) + * @param userid user identifier + * @param enabledChannels a map of the channels to which reach the user per notification, empty array or null values to set the key notification type off + * @return true if everything was fine + */ + boolean setUserNotificationPreferences(String userid, Map enabledChannels); + /** + * get the notification preferences map (enableor disable the channels to be used for notifying the user) + * @param userid user identifier + * @return the map + * @throws NotificationTypeNotFoundException self explaining + * @throws NotificationChannelTypeNotFoundException self explaining + */ + Map getUserNotificationPreferences(String userid) throws NotificationTypeNotFoundException, NotificationChannelTypeNotFoundException; + + /** + * @param commentId comment unique identifier + * @return the comment belonging to the commentId + * @throws CommentIDNotFoundException + */ + Comment readCommentById(String commentId) throws CommentIDNotFoundException; + /** + * add a comment to a feed + * @param comment the Comment instance to add + */ + boolean addComment(Comment comment) throws FeedIDNotFoundException; + /** + * @deprecated use getAllCommentByPost + * @param feedid feed identifier + * return all the comments belonging to the feedid + */ + List getAllCommentByFeed(String feedid); + /** + * @param postid the post identifier + * return all the comments belonging to the postid + */ + List getAllCommentByPost(String postid); + /** + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return a list of comments (sorted starting from the most recent one) made by the user since timeInMillis up to now + */ + List getRecentCommentsByUserAndDate(String userid, long timeInMillis) throws Exception; + /** + * edit a comment + * @param comment the comment to edit + * @return true if success, false otherwise + */ + boolean editComment(Comment comment) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, CommentIDNotFoundException, FeedIDNotFoundException; + /** + * deletes a comment + * @param commentid the comment identifier to delete + * @param feedid the feedid to which the comment is associated + * @return true if success, false otherwise + */ + boolean deleteComment(String commentid, String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, CommentIDNotFoundException, FeedIDNotFoundException; + /** + * add a like to a feed + * @param like instance + * @throws FeedIDNotFoundException + */ + boolean like(Like like) throws FeedIDNotFoundException; + /** + * unlike a feed + * @param userid user identifier + * @param likeid the like identifier to delete + * @param feedid the feedid to which the comment is associated + * @return true if success, false otherwise + */ + boolean unlike(String userid, String likeid, String feedid) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, ColumnNameNotFoundException, LikeIDNotFoundException, FeedIDNotFoundException; + /** + * @deprecated use getAllLikedPostIdsByUser + * @param userid user identifier + * return all the feedids a user has liked + */ + List getAllLikedFeedIdsByUser(String userid); + /** + * @param userid user identifier + * return all the feedids a user has liked + */ + List getAllLikedPostIdsByUser(String userid); + /** + * @deprecated use getAllLikedPostsByUser + * @param userid user identifier + * @param limit set 0 to get everything, an int to get the most recent -limit- liked feeds + * @throws ColumnNameNotFoundException . + * @throws FeedIDNotFoundException . + * @throws FeedTypeNotFoundException . + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedIDNotFoundException . + * return all the feeds a user has liked + */ + List getAllLikedFeedsByUser(String userid, int limit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + + /** + * @param userid user identifier + * @param limit set 0 to get everything, an int to get the most recent -limit- liked posts + * @throws ColumnNameNotFoundException . + * @throws FeedIDNotFoundException . + * @throws FeedTypeNotFoundException . + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedIDNotFoundException . + * return all the feeds a user has liked + */ + List getAllLikedPostsByUser(String userid, int limit) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + + /** + * @deprecated use getRecentLikedPostsByUserAndDate + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return the likes made to feeds in the range from: today to: timeInMillis + */ + List getRecentLikedFeedsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException; + /** + * @param userid user identifier + * @param timeInMillis time in milliseconds from which you want to start retrieve the feeds + * @return the likes made to feeds in the range from: today to: timeInMillis + */ + List getRecentLikedPostsByUserAndDate(String userid, long timeInMillis) throws IllegalArgumentException; + /** + * @deprecated use getAllLikesByPost + * @param postid postid identifier + * return all the likes belonging to the postid + */ + List getAllLikesByFeed(String postid); + /** + * @param postid postid identifier + * return all the likes belonging to the postid + */ + List getAllLikesByPost(String postid); + /** + * + * @param hashtags the hashtag including the '#' + * @param postid the postid to which the hashtag is associated + * @param vreid VRE identifier + * @return true if success, false otherwise + * @throws FeedIDNotFoundException + */ + boolean saveHashTags(String postid, String vreid, List hashtags) throws FeedIDNotFoundException; + /** + * + * @param hashtags the hashtag including the '#' + * @param commentId the commentId to which the hashtag is associated + * @param vreid VRE identifier + * @return true if success, false otherwise + * @throws CommentIDNotFoundException + */ + boolean saveHashTagsComment(String commentId, String vreid, List hashtags) throws CommentIDNotFoundException; + /** + * + * @param hashtags the hashtag including the '#' + * @param postid the postid to which the hashtag is associated + * @param vreid VRE identifier + * @return true if success, false otherwise + * @throws FeedIDNotFoundException + */ + boolean deleteHashTags(String postid, String vreid, List hashtags) throws FeedIDNotFoundException; + /** + * + * @param hashtags the hashtag including the '#' + * @param commentId the commentId to which the hashtag is associated + * @param vreid VRE identifier + * @return true if success, false otherwise + * @throws CommentIDNotFoundException + */ + boolean deleteHashTagsComment(String commentId, String vreid, List hashtags) throws CommentIDNotFoundException; + /** + * get a map of vre hashtags where the key is the hashtag and the value is the occurrence of the hashtag in the VRE + * @param vreid vre identifier (scope) + * @return a HashMap of vre Hashtags associated with their occurrence + */ + Map getVREHashtagsWithOccurrence(String vreid); + /** + * get a map of vre hashtags where the key is the hashtag and the value is the occurrence of the hashtag in the VRE + * @param vreid vre identifier (scope) + * @param timestamp do not consider hashtags used before timestamp + * @return a HashMap of vre Hashtags associated with their occurrence + */ + Map getVREHashtagsWithOccurrenceFilteredByTime(String vreid, long timestamp); + /** + * @deprecated use getVREPostsByHashtag + * @param vreid VRE identifier + * @param hashtag the hashtag to look for including the '#', it is case sensitive + * @throws ColumnNameNotFoundException . + * @throws FeedIDNotFoundException . + * @throws FeedTypeNotFoundException . + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedIDNotFoundException . + * @return all the feeds having the hashtag passed as parameter + */ + List getVREFeedsByHashtag(String vreid, String hashtag) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + /** + * + * @param vreid VRE identifier + * @param hashtag the hashtag to look for including the '#', it is case sensitive + * @throws ColumnNameNotFoundException . + * @throws FeedIDNotFoundException . + * @throws FeedTypeNotFoundException . + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedIDNotFoundException . + * @return all the feeds having the hashtag passed as parameter + */ + List getVREPostsByHashtag(String vreid, String hashtag) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException; + + /** + * Save the invite for a given email into a given vre + * @param invite the invite object instanc to save + * @return {@link InviteOperationResult} SUCCESS, FAILED or ALREADY_INVITED (if an invite is sent to en existing email in the same environment more than once) + */ + InviteOperationResult saveInvite(Invite invite) throws AddressException; + /** + * + * @param vreid the environment where you want to check the invite + * @param email the email of the invite to check in the environmnet + * @return the InviteId if present, null otherwise + */ + String isExistingInvite(String vreid, String email); + /** + * read an invite from a given id + * @throws InviteIDNotFoundException + * @throws InviteStatusNotFoundException + */ + Invite readInvite(String inviteid) throws InviteIDNotFoundException, InviteStatusNotFoundException; + /** + * set the status of an invite, see {@link InviteStatus} + * @throws InviteIDNotFoundException + */ + boolean setInviteStatus(String vreid, String email, InviteStatus status) throws InviteIDNotFoundException, InviteStatusNotFoundException; + /** + * Use to get the list of invites per VRE + * @param vreid the vre id + * @param status optional, if you want to restict on the status, e.g. all pending invites + * @return return the list of invites + * @throws InviteIDNotFoundException + * @throws InviteStatusNotFoundException + */ + List getInvitedEmailsByVRE(String vreid, InviteStatus... status) throws InviteIDNotFoundException, InviteStatusNotFoundException; + /** + * + * @param feedId + * @return the list of attachments of the feed feedId, starting from the second one (first attachment is included in Feed instance already) + */ + List getAttachmentsByFeedId(String feedId) throws FeedIDNotFoundException; + + /** + * Retrieve all the ids of the vre + * @return the set of ids of the vre available or empty list in case of errors. + */ + public List getAllVREIds(); + + /** + * close the connection to the underlying database + */ + void closeConnection(); +} diff --git a/target/classes/org/gcube/portal/databook/server/RunningCluster.class b/target/classes/org/gcube/portal/databook/server/RunningCluster.class new file mode 100644 index 0000000000000000000000000000000000000000..4abcaa69efaeedb10b6956899b4d0b2a9427c057 GIT binary patch literal 6971 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 resources = getConfigurationFromIS(infrastructureName); + if (resources.size() > 1) { + _log.error("Too many Runtime Resource having name " + RUNTIME_RESOURCE_NAME +" in this scope "); + throw new TooManyRunningClustersException("There exist more than 1 Runtime Resource in this scope having name " + + RUNTIME_RESOURCE_NAME + " and Platform " + PLATFORM_NAME + ". Only one allowed per infrasrtucture."); + } + else if (resources.size() == 0){ + _log.error("There is no Runtime Resource having name " + RUNTIME_RESOURCE_NAME +" and Platform " + PLATFORM_NAME + " in this scope. Using default configuration properties: " + DEFAULT_CONFIGURATION); + loadDefaultConfiguration(); + } + else { + for (ServiceEndpoint res : resources) { + AccessPoint found = res.profile().accessPoints().iterator().next(); + host = found.address(); + clusterName = found.description(); + keyspaceName = found.name(); + } + } + } catch (Exception e) { + e.printStackTrace(); + }*/ + + host = "10.1.28.55:9042, 10.1.30.142:9042, 10.1.28.100:9042"; + datacenterName = "1"; + keyspaceName = "dev_mig_new_schema_test"; + } + + /** + * + * @return the + * @throws Exception + */ + private List getConfigurationFromIS(String infrastructureName) throws Exception { + _log.debug("getConfigurationFromIS infrastructureName="+infrastructureName ); + String scope = "/"; + if(infrastructureName != null && !infrastructureName.isEmpty()) + scope += infrastructureName; + else { + scope += readInfrastructureName(); + _log.debug("infrastrucute name is null, setting root scope=" + scope); + } + String currScope = ScopeProvider.instance.get(); + ScopeProvider.instance.set(scope); + SimpleQuery query = queryFor(ServiceEndpoint.class); + query.addCondition("$resource/Profile/Name/text() eq '"+ RUNTIME_RESOURCE_NAME +"'"); + query.addCondition("$resource/Profile/Platform/Name/text() eq '"+ PLATFORM_NAME +"'"); + DiscoveryClient client = clientFor(ServiceEndpoint.class); + List toReturn = client.submit(query); + ScopeProvider.instance.set(currScope); + return toReturn; + } + + private String readInfrastructureName() { + + Properties props = new Properties(); + try { + StringBuilder sb = new StringBuilder(getCatalinaHome()); + sb.append(File.separator) + .append(PortalContext.CONFIGURATION_FOLDER) + .append(File.separator) + .append(PortalContext.INFRA_PROPERTY_FILENAME); + String propertyfile = sb.toString(); + File propsFile = new File(propertyfile); + FileInputStream fis = new FileInputStream(propsFile); + props.load( fis); + return props.getProperty(GCubePortalConstants.INFRASTRUCTURE_NAME); + } + catch(IOException e) { + _log.error("infrastructure.properties file not found under $CATALINA_HOME/conf/ dir, setting default infrastructure Name " + "gcube"); + return "gcube"; + } + } + + + /** + * + */ + private void loadDefaultConfiguration() { + Properties props = new Properties(); + try { + props.load(CassandraClusterConnection.class.getResourceAsStream(DEFAULT_CONFIGURATION)); + host = props.getProperty(HOST_PROPERTY) + ":" + props.getProperty(HOST_PORT_PROPERTY); + datacenterName = props.getProperty(DATACENTER_NAME_PROPERTY); + keyspaceName = props.getProperty(KEY_SPACE_NAME_PROPERTY); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + + public String getKeyspaceName() { + return keyspaceName; + } + + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + @Override + public String toString() { + return "RunningCluster [host=" + host + ", datacenterName=" + datacenterName + + ", keyspaceName=" + keyspaceName + "]"; + } + /** + * + * @return $CATALINA_HOME + */ + private static String getCatalinaHome() { + return (System.getenv("CATALINA_HOME").endsWith("/") ? System.getenv("CATALINA_HOME") : System.getenv("CATALINA_HOME")+"/"); + } + public void setDatacenterName(String datacenterName){ + this.datacenterName = datacenterName; + } + + public String getDatacenterName() { + return datacenterName; + } + + public List getHosts() { + List hosts = new ArrayList<>(); + String [] ips = host.split(", "); + for (String ip: ips){ + String[] ip_port = ip.split(":"); + hosts.add(new InetSocketAddress(ip_port[0], Integer.parseInt(ip_port[1]))); + } + return hosts; + } +} \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/server/Schema.class b/target/classes/org/gcube/portal/databook/server/Schema.class new file mode 100644 index 0000000000000000000000000000000000000000..c757945fa5f0af13163004717403c8c330bc11ca GIT binary patch literal 3102 zcma);=X={!6o-%6Bvw|NCWTTcg|a$;no(xUa2=&lD-SF=5SCD6B~~L#MwSC%@4ffl zdzV!xP&OamTNsUhvKJdlQeXq_v_w4Jx|2c4wh_=yR8CoXM#vq)@&e-iKC)*6d z$nvr^E3&47U^d%w!Z|0*>UP~}SQ+Y)XlSoBXJtLhpUIY{_BwVX(O|J;sAFnAXQ-v3 zF43^ok;L0mxuT3I6{VOL zf!ZR`x+NEuLuc9v9p4tw8ye5)<3?_mZstqXqM=k|I$ffb<5sI4Su?GC(DoxI?8xov zczi}jZpNvl2^~rG3As*g&qkV3l@RS@S>(uENb9*0^=NiXzLdr$v;BPZq{P#Vct{7M*MCw(H0bjNv<=^89;ku4k)g&E6U zhxn(~U?p6h-xRW6DpiE+7kLlDM03bpu&QlD9%vilb=lg;d{$!!5_JIpLv%59CWl zqf*jPkfSi`PF!yXeiR0t9n@gmP^x0As%d6o`aKe@NR&*sJuh*hmwmqgLvsnA{q#0;MGu#$+#Fl!`*l`+-P2SnJHJ)iClhCrhR~B z=+0U8Jd_lwnxUFws-~FLvQ`q)^=p{XXnW$7@|J6N`12^QK3Yyc56}j8}n27_SB&$#@NTE#sp>>lhykK92G6;1d|12tJwdDd0_vH-k@Q zd>VKw<1F}0#%F=IF+K-;9^>=D7c$-szKHR~;7b|jzW!~crkfq30bztQg?iT=RvGWzph!ZUAS literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/server/Schema.java b/target/classes/org/gcube/portal/databook/server/Schema.java new file mode 100644 index 0000000..522093e --- /dev/null +++ b/target/classes/org/gcube/portal/databook/server/Schema.java @@ -0,0 +1,68 @@ +package org.gcube.portal.databook.server; + +public class Schema { + //Tables + public static final String NOTIFICATIONS = "Notifications"; + public static final String POSTS = "Posts"; + public static final String COMMENTS = "Comments"; + public static final String LIKES = "Likes"; + public static final String INVITES = "Invites"; + public static final String VRE_TIMELINE_POSTS = "VRETimeline"; + public static final String USER_TIMELINE_POSTS = "UserTimeline"; + public static final String APP_TIMELINE_POSTS = "AppTimeline"; + public static final String USER_LIKED_POSTS = "UserLikes"; + public static final String USER_NOTIFICATIONS = "UserNotifications"; // regular user notifications timeline (both read and unread, messages are included) + public static final String USER_NOTIFICATIONS_UNREAD = "UserUnreadNotifications"; // only unread user notifications/ notifications messages + public static final String USER_NOTIFICATIONS_PREFERENCES = "UserNotificationsPreferences"; // preferences for notifications + public static final String HASHTAGS_COUNTER = "HashtagsCounter"; // count the hashtags per group and type + public static final String HASHTAGGED_POSTS = "HashtaggedPosts"; // contains hashtags per type associated with vre and POST + public static final String HASHTAGGED_COMMENTS = "HashtaggedComments"; // contains hashtags per type associated with vre and comment + public static final String VRE_INVITES = "VREInvites"; //contains the emails that were invited per VRE + public static final String EMAIL_INVITES = "EmailInvites"; //contains the list of invitation per email + public static final String ATTACHMENTS = "Attachments"; //contains the list of all the attachments in a POST + + //columns + public static final String USER_ID = "userid"; //text + public static final String TYPE = "type"; //text + public static final String PREFERENCE = "preference"; //text + public static final String TIMESTAMP = "timestamp"; //timestamp + public static final String NOT_ID = "notid"; //UUID + public static final String VRE_ID = "vreid"; //text + public static final String POST_ID = "postid"; //UUID + public static final String APP_ID = "appid"; //text + public static final String HASHTAG = "hashtag"; //text + public static final String COMMENT_ID = "commentid"; //UUID + public static final String COUNT = "count"; //big int + public static final String LIKE_ID = "likeid"; //UUID + public static final String INVITE_ID = "inviteid"; //UUID + public static final String STATUS = "status"; //text + public static final String EMAIL = "email"; //text + public static final String ATTACH_ID = "attachid"; //UUID + public static final String URI = "uri"; //text + public static final String NAME = "name"; //text + public static final String DESCRIPTION = "description"; //text + public static final String URI_THUMBNAIL = "urithumbnail"; //text + public static final String MIME_TYPE = "mimetype"; //text + public static final String SENDER_USER_ID = "senderuserid"; //text + public static final String CONTROL_CODE = "controlcode"; //text + public static final String SENDER_FULL_NAME = "senderfullname"; //text + public static final String FULL_NAME = "fullname"; //text + public static final String THUMBNAIL_URL = "thumbnailurl"; //text + public static final String COMMENT = "comment"; //text + public static final String IS_EDIT = "isedit"; //bool + public static final String LAST_EDIT_TIME = "lastedittime"; //timestamp + public static final String SUBJECT_ID = "subjectid"; //text + public static final String SENDER_ID = "senderid"; //text + public static final String SENDER_THUMBNAIL_URL = "senderthumbnailurl"; //text + public static final String IS_READ = "isread"; //bool + public static final String LINK_HOST = "linkhost"; //text + public static final String LIKES_NO = "likesno"; //big int + public static final String LINK_DESCRIPTION = "linkdescription"; //text + public static final String IS_APPLICATION_POST = "isapplicationpost"; //bool --> + public static final String ENTITY_ID = "entityid"; //text + public static final String PRIVACY = "privacy"; //text + public static final String MULTI_FILE_UPLOAD = "multifileupload"; //bool + public static final String COMMENTS_NO = "commentsno"; //big int + public static final String LINK_TITLE = "linktitle"; //text + +} \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/server/Tester.class b/target/classes/org/gcube/portal/databook/server/Tester.class new file mode 100644 index 0000000000000000000000000000000000000000..51ae327ca57d049156d7afba00379717c5fdb4c4 GIT binary patch literal 3348 zcmbVOYj+#f72Vf%Job37jq(nV7lz0tifqNPV`NMc#ZKHR&ch~cNMBddwKBKTOPlg zEe6%93i-5Wy6m~W8_fuGriX6|bQOY%vhfH8Ec6TP*PdH#=46?q)*KAtQGwp7iefB* zr_#lZ5DFgYfvDqNB!kCBpNS$a2R=<0Q{**$F-+UUdq z2m4@KI3#fP|IJAc9%pJzS!^7{VGVgiU~en^#VB`p+gh3<+huNBpb@|M=>?VwHy3Jh-8CF@l-EHci3ro}< zJSQ+TIzCyR7#*u*a=EFo%=pygcxEb>8_!fGCQs)|W6LF#o6xFx-oZJXC!tWu%C(?D zPx*EN+NyKof@-;n<@gwaiLsaZ|E>qgms`>B9^7i3JXt{>|JS{1mt7bU6rTW%-W4 z(Ins>0MbS6uQPY^m8IZ?ItQy69~%=W=`vPVmx#l7ho#_b&;|u6t0fYXUN-XP`NY0S zX4Ld|-ksjwTTw zK^?!=ogBm!64>)VGv?!$)J;pYp_Rzd+|_Klj7XFPMs}W88c-7Fwl~<4E{pTXVkFD= zuE@HnwT0hp9y;bz!GJtjD^=vss6ZyYz0(JI9=>VgW&Fv)9|h9eW;U^M@QTi%Mb#{+ zRkoeI7&ODOnsfC>v@bqYoYK8OsuzMFYDA%|Us2JWpwh7MI{s$iuL8$6y2bTZf_o}k zG%@f+sx0}=zkxRiS=-nW_^MS}iDe9anI{lWHHL~j<238}xG7r8+Oo6BP>=uC*LVIf zcDc1}GLsCE1i2tRZ_$lZexMt#4dSZ)%KXE@@9`2h{yvD81e|%_SD`t{D1M&*#Usx5 z64owk3;z~4y!EU4TxN2FV|3ifQQ84pA2ayR)~6%hyLs*9is|QSn0Ni_O^Hw7e2mnG zTy$U$uifU6gS}=4T=9^Um=y@F4Idr3kNuzH;H}hS_wmHXIJ#lpZ~XV83j;jW4H_6H zHo|c{N#kA&;VC+Mn*VLScYW}>oxO<=b8tp`Cy7&=}(%H-v-c!@-xUldM=1#8T zN14xX4fqsG9nd5?O_C0o+#cfUG4g(bdx!b&2xB^G$c)6WNyMFu_(j|%l|DR31}uZXHM6z@px2$UYC{C^3>W2tgNQIVoy_5u1y(#@>HTSxdI%{q~y`x@`M zk}=8STs=+4C-^MQe2tLe$rh5w9+EtaC?RR1i4{85mH!P^iLgez-RSs+h8-4!h2QE+ z%^tM1%1vaz8JcK$^pW7mI{si-ZPwKh<2e>YpYfto`YMe&@Mrvmcm3=w?!Aq7@Gjot Oj#l44@jm{8gWm!}+jFY` literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/server/Tester.java b/target/classes/org/gcube/portal/databook/server/Tester.java new file mode 100644 index 0000000..522de5b --- /dev/null +++ b/target/classes/org/gcube/portal/databook/server/Tester.java @@ -0,0 +1,45 @@ +package org.gcube.portal.databook.server; + +import org.gcube.portal.databook.shared.*; +import org.gcube.portal.databook.shared.ex.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class Tester { + private static DBCassandraAstyanaxImpl store; + private static Logger LOGGER = LoggerFactory.getLogger(Tester.class); + + public Tester() { + store = new DBCassandraAstyanaxImpl("gcube"); //set to true if you want to drop the KeySpace and recreate it + } + + public static void main(String[] args) throws ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException, FeedIDNotFoundException, FeedTypeNotFoundException { + Tester test = new Tester(); + //test.getComment(); + test.testFunc(); + System.exit(0); + + } + public void testFunc() throws ColumnNameNotFoundException, PrivacyLevelTypeNotFoundException, FeedIDNotFoundException, FeedTypeNotFoundException { + String postIdToUpdate = "047c601d-2291-4974-9224-d6732b1fbe26"; + Post read = store.readPost(postIdToUpdate); + + List readC = store.getAllCommentByPost("047c601d-2291-4974-9224-d6732b1fbe26"); + System.out.println(read); + readC.forEach(c -> System.out.println(c.getText())); + } + public void getComment(){ + String uuid = "820969b2-4632-4197-9fd6-5aafab781faa"; + + Comment c; + try { + c = store.readCommentById(uuid); + System.out.println(c); + } catch (CommentIDNotFoundException e) { + // TODO Auto-generated catch block + System.err.println(e.toString()); + } + } +} \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/server/resources/databook.properties b/target/classes/org/gcube/portal/databook/server/resources/databook.properties new file mode 100644 index 0000000..c0fad71 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/server/resources/databook.properties @@ -0,0 +1,4 @@ +host = node1.d.cassandra.research-infrastructures.eu +port = 9160 +cluster = D4Science Cluster +keyspace = DevKeySpace \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/shared/ApplicationProfile.class b/target/classes/org/gcube/portal/databook/shared/ApplicationProfile.class new file mode 100644 index 0000000000000000000000000000000000000000..8992abbb12d27862c754cdcfbef8b304ef331bd4 GIT binary patch literal 2256 zcmcJP?QR=I7=_Oy{;IP$!A;xPb=_@Bo!E7{P&d$$CT-I;G>s{skVpveV{I?)wvN|Y z+emN=+z3BG!mR`n7r;d!&O2-3uwMT`LY8OFe7?^+b7uei>$g7u+`*?w%qi47ziqXf z!-iw^Jbz$!td>2n8=m*t>c6yor)53r^*V0T9=KljbKm>c?Knxq6qa7u-`Q5j?zXMZ z8n2w@Ac=&+vhH;~>(KFCyW{>~H#&~O{A=fXg=~GY=5XM<-S(D3tZSce#zM>KH+{D! zVH8sCiQRUN{EkAr-}HL2#ZX#_`)=1A?6A3BKIY=bUdu^i9$5n!EGjJ4-LCUuc+znE zFN4t8y4SQj$2M_@GVY8GUb=mS&H8`Hp3L6*bSD2_Px<&96mkZVNQt^^;9Q`t7)S@| zs)2<-T{B<=>bike|MGfynv&!F@%V*^wB(eN+~9@2r6i{YD#N}fXRj>7 zp?`HOaK`@WH7;;?(n@jcFu2zg2gXuB^_>fm7O8<37$u223YWt6*&Vu_mgA@Jp~A|v zPtC7syX`b;xGVNp6ZNryE!=0)cCY7jTM8RdNlzWqIMP-M^j@-RifOk~c&L!6nrE!b zzFnHRYW`zjc08e1Ei4j&O z5mq%!o)In+yucl=;5>@R;VOS7ZZJuS{EX>w_iNtw<0v46+poVnu_PVUQhyJeUC@wiS@~BSBWf zAiI$uA4G$kd4GXfpAuwm28g^G0pWLvA*?yAB|B2)C_#2|MvMe^jm7Y%nC;pU7>Q+sIlY*Za)YH3h@xWy0h$?4s30(C0qDW}=Ml!GPD;O+!fZJH1K`J2Y5)KL literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/Attachment.class b/target/classes/org/gcube/portal/databook/shared/Attachment.class new file mode 100644 index 0000000000000000000000000000000000000000..8424be8a31f9df96815377957212dc22e35cadc9 GIT binary patch literal 2345 zcmcJRU2hsk7=_PZSTNoimpC7|u7im~Y>d50ouq9XJ0EsFaET+;j;kt-lm%9JQ`kkz zQmMJ=-|1y5g+ywl{(%0ds%K_N!0Y8A7r9{O?7Q#GJnzhz761PC*FONR<7pBxfmPRQ z8qIpIW*HsV^UapgFnzP;x<4D;W7D%5#y#IR>&I=&@so%P%)ByxF^!h#G>xaVS5}=- zO<-0(HAQ<zK#uce<>Da_=7G!ohmcyM{iz@xpUJX{*Oo6^jmh;lFTPfTXm@el> ze9PE!B@gOlDZbx-6F0q2f4} zx6?AaU8|eK6M^lI@a@uYzP+yN*sm>*H}Z54i}ct8e+g)aNz?Ho5tEivJq@RN+D-K| zo9byb_8E@j1!OzJrw#UkeWLUZpZ}@S&ah2$I$#!YoMj98RVDH19G~O_=h?~$epdiM zQBF`=?c+kJ+{avLt&jOqF5bsNDVOLYU&?8H6oxAl6wD%5C=mP-XI#P=Tt*H>T*MWs zWwr8SmdDu#D@!HIl{7_Fu;eVtJH`!>N){bgN|v2aN*1nh%o1k}s15c(*>7;+4<^O9 zI8+j_8d-9YP{H7BX3J$YRqn8)VAIyQsG(*!7i4`v*9Pc;1Eoli`7p?>NRZWNkohpk9fI5)10oMjf|Mgc7Q!IAksxc)APZrT3PJY9 zfJom+ko8EAd>CXu62yoG$%jD>2y!?EMA}w@T#W=Ngh76Y1i2OsGIIX{vpy%tPh&vj zt&t%7?y;Sr;eS&f9iZ|zHh#?Bc!#e`Z!q^3-)6ViP|r(!C(sL0-wSkJ>YYFrq<+BW sEglVv$*N2Hl3zBHe|KtlfR`hMRR(t`hKjnYd-#rhnpjo-_O;3X0R_T>Q~&?~ literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/Attachment.java b/target/classes/org/gcube/portal/databook/shared/Attachment.java new file mode 100644 index 0000000..5b8e337 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/Attachment.java @@ -0,0 +1,104 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; + +import org.jsonmaker.gwt.client.Jsonizer; + +@SuppressWarnings("serial") +public class Attachment implements Serializable { + + public interface AttachmentJsonizer extends Jsonizer {} + + private String id; + private String uri; + private String name; + private String description; + private String thumbnailURL; + private String mimeType; + + public Attachment() { + super(); + } + + /** + * @param id the id in the cassandra CF + * @param uri where you can download the file from + * @param name the name of the attached file + * @param description the description of the attached file + * @param thumbnailURL the URL of the image representing the attached file + * @param mimeType the type of file + */ + public Attachment(String id, String uri, String name, String description, + String thumbnailURL, String mimeType) { + super(); + this.id = id; + this.uri = uri; + this.name = name; + this.description = description; + this.thumbnailURL = thumbnailURL; + this.mimeType = mimeType; + } + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + + public String getName() { + return name; + } + + + public void setName(String name) { + this.name = name; + } + + + public String getDescription() { + return description; + } + + + public void setDescription(String description) { + this.description = description; + } + + + public String getThumbnailURL() { + return thumbnailURL; + } + + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + @Override + public String toString() { + return "Attachment [uri=" + uri + ", name=" + name + ", description=" + + description + ", thumbnailURL=" + thumbnailURL + + ", mimeType=" + mimeType + "]"; + } + + + + +} diff --git a/target/classes/org/gcube/portal/databook/shared/ClientAttachment.class b/target/classes/org/gcube/portal/databook/shared/ClientAttachment.class new file mode 100644 index 0000000000000000000000000000000000000000..9ba29a88944e6f6a8f0d897a1059c3a162776a17 GIT binary patch literal 1086 zcmcIiYikoh6g`tBlSfxut5vt})>qTlV)c_PLMezyu+Y|mew%EDWa?%&>`n^(IsO9$ zLqWkG;Exi|>=p`&9~As@&z+h3IOop&{^QFx08bHAQ4)BZq}`w!4%<2yB&k(V&{0;k zljMDn^;D`m!G2_PZ1=2HVXsfGin74usX9|Zq~dOH&_30n6)2gGz*Ot%;mD>Y?(PVT z4O1gfj#Xa^jCXVvre`pZe^~up z*Z;d|{u5dMa2Q*T@5E$=`uE~EvC2)E@|RnunTf4VlR==a9)efd!I@4Yb-vR8KebLX z>!AYaym=4R!dvuEE4*b7^}@U7p;34bJd8sMh(w@qlnm2QzcB7Yrhi?XEw>y33x8ze zzMgZhnd~*GpXo7fst~BV)yW1bWYOAgH%i(n;%3NV^{`B`E>aT7-Q_suIg)pdWSt{9 z=SarH5+k`ywAXnGh=N#IyTHV!{P_m0D+>-_iq(=T)Lo)0^qF^6 z;`UdFw-@lANnfswFyqVh5$1fkF~Wi`H%D0VrC%Olg-{vczAryAs|43|g&hH(J!UY0 zS$3MEou}9ZtYVR5mvTlgi%yrq*)x~!7;n2zV>RbF`EEqp?$c1tJvV|1Uz&JGH7@cI Z?@O%i^h{G}lR0beu#Sxko2X^j`U!D3?GOL} literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ClientAttachment.java b/target/classes/org/gcube/portal/databook/shared/ClientAttachment.java new file mode 100644 index 0000000..13acb08 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ClientAttachment.java @@ -0,0 +1,34 @@ +package org.gcube.portal.databook.shared; + +import jsinterop.annotations.JsOverlay; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object") +public class ClientAttachment { + public String id; + public String uri; + public String name; + public String description; + public String thumbnailURL; + public String mimeType; + /** + * @param id the id in the cassandra CF + * @param uri where you can download the file from + * @param name the name of the attached file + * @param description the description of the attached file + * @param thumbnailURL the URL of the image representing the attached file + * @param mimeType the type of file + */ + @JsOverlay + public static ClientAttachment create(String id, String uri, String name, String description, String thumbnailURL, String mimeType) { + ClientAttachment o = new ClientAttachment(); + o.id = id; + o.uri = uri; + o.name = name; + o.description = description; + o.thumbnailURL = thumbnailURL; + o.mimeType = mimeType; + return o; + } +} diff --git a/target/classes/org/gcube/portal/databook/shared/ClientFeed$ClientFeedJsonizer.class b/target/classes/org/gcube/portal/databook/shared/ClientFeed$ClientFeedJsonizer.class new file mode 100644 index 0000000000000000000000000000000000000000..662742e5d0e327e9c052ea2f9307b8ab3ba50d3f GIT binary patch literal 295 zcmb7=!D<3Q42J($>r`t|e1k%71#|K2MG)Fc4}F5{ZdiAn&dAJY!AJAZ2k1kUj)Lsj zLz176eEG@m-{}Xy0#61#!qSJD>vCTx?|evNxsoJ>_gjt|30m>WHtNz^wR-8~d-Se3 zYB1;%rmY-=t+<*$idM^HFd#gi$!(tdlC1`=zY~`i6knGKqffsNrLG&Rgh_{=pNWL= un{yggR$|m>@JM*Q!7gFe5wAD1F~VJr`}_o;2Xn~}80I?4{cH;3!SEkRuT@+C literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ClientFeed.class b/target/classes/org/gcube/portal/databook/shared/ClientFeed.class new file mode 100644 index 0000000000000000000000000000000000000000..c5b7dbfdcb64ea7a143ddb5dbbb374565a076ce5 GIT binary patch literal 5303 zcmd^>TXPge6vxlxvX^8?;)aXsjfh~9$%Z9_5JE^|5`tX9HOVR<>LfcP1DoBjJBt!Q z1w{cxMMc3XAN0WoeE^h!Dy{MZ_?4)#{GaYgc6ZWSAP>Iyu-pGR-P8T+b9&C{zyALH zPa@hxH-c25QClWE9iN`cPg?Q0Ox7_|@ucaPlbOuPcy7kbTFLlu%C^$Z4$DdgsY;`U z6Xt0%o-)(Z@%@u0tSKi*0gaXmtDT9DSy|gm+4JUP%F?Lvq;*E4$Y|l6F(+%Mr+YQ3 za?Z?QL?EBT8%ch)XYt%1$L1Y772j?;7DiU)v$jUHNh>#%wdWi=lh!D7JfBMKGx?2b zYu2<=8tKkVes(eqJ#lDMqj1VjpB%Rx#;9k#z4-kGwoGJG;|uR#N;d7xC)4(6K)7Cz0&dQEUzeYwgQ)Vh*!q@P#XRLB&Y~Z#(eEmX5vHF9SrQvyW zOCeB?{*E|2-a+{9-x9u#{w~I`otnYB6HRV)m;=ci}07z7d%YL+J2i zJ*Abe39lj6s@N$e20?6g@_~-V%_AH>Skc=#4DRt&QH$QY-I-7x9v=H%30O z9|~y_X|2@1ULGDSar)zBUv_ZGN+qFMNE9?w9Kgp}iQ^q|GBWQ4X-1<}{<1ifw^KfVZ4Y!A8Sf2oK#po#@UdTqJs$gWsMr8z4+9j z;}fwgPr*kGhO2_DsOH1=xklPCcJwu!j?=J4HDj54cFNjeiwi{|IO{oxfZCN#TiM~1 znaf$ZAbq1z|3j|Z>Ph_c)o=0x2#IG7jwSrSIu5uNeh((JuELtRC z(IN$l7719iNWY>*@)a#ouV|5YMT@j6S|nZ3BISw}2^VWVDRh)pL*rh8|7T$7M602# zHty52cf^p@_^$yL(ORmab<_l<%R$({8a(j?FJOe6axG7!9l>)w`Vu^m(dN=RBj!@G z(e6^K5v_8m&4^aJ)NVurF2#*#(4`I|8gi-Ah=yJ2GNLsubsN!ImwJq-?ozK2UFK4s z5v_A+fXOO>PBettL(~Sc7#!CQN3KV`iBps|puYpW8`0YdwTZf^i~49Y4MXjsEwrC{ zXo9wi9o>+$-j2X6!ojXch=B0^6I>awE-Ma7l~5d(YN0qV0iifFL7_M}?Dhm#M$E*D z15_gvhp1L44ibks!Icr!mK6u8js~Hnzu6LnMZ>O#@y`K^qh-o!<1Vec4N)Q75)j5d zu{D3Nw$q6Baz94%#sVTh{%{XsTSH=om2%Xga{``oG}@sAY4(GRC_!FUgEad=b^&B} z84&(h*aJJ2Agz9oy-JW>YLHex$U%S{Dg(ktgF$xF9{l@5)8+@6P=buoUhn0S(6sqM z4g=&!84y0146;w@k#;}GF(t@;wMW|hASOU2%Yg8Q!5{~eAaOs4r35*s28sJYY=E37 z1H#`WgB((VbofDLl^|nkkPbh{DS%|lfN)x1kZ~nQrynG*1es8SboxQg0A#)l2xlb* zNhm?O{2=F)Ag`!Fy8IyL0dk=X2q#4bc~uG0?FYH21Uak*>Gp$M2FR5%Ae@sKGOkp zuLOBR4btZa`2iq5mI2{{$RKZ$i8>@N8Iwyg?0_HWCneAnB^M{L#3TpsyjTQ_ZWi*+ z^E1GHDFY@iQiCXQ}}~!W}TC| zm33a~wtMteWM1lawx5+c&iY-cJ6OLjbtmf!Qg^ZbQ0i{hA4%QA`jXVWtglGj$NE#L z2YB7jpzqNa1(&Wt42W*w25=h@y#puyN@wXex attachments; + + public ClientFeed() { + super(); + } + + public ClientFeed(String key, String type, String userid, Date time, + String uri, String description, String fullName, String email, + String thumbnailURL, String linkTitle, String linkDescription, + String linkUrlThumbnail, String linkHost, List attachments) { + super(); + this.key = key; + this.type = type; + this.userid = userid; + this.time = time; + this.uri = uri; + this.description = description; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.linkTitle = linkTitle; + this.linkDescription = linkDescription; + this.linkUrlThumbnail = linkUrlThumbnail; + this.linkHost = linkHost; + this.attachments = attachments; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUserid() { + return userid; + } + + public void setUserid(String userid) { + this.userid = userid; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String getLinkTitle() { + return linkTitle; + } + + public void setLinkTitle(String linkTitle) { + this.linkTitle = linkTitle; + } + + public String getLinkDescription() { + return linkDescription; + } + + public void setLinkDescription(String linkDescription) { + this.linkDescription = linkDescription; + } + + public String getLinkUrlThumbnail() { + return linkUrlThumbnail; + } + + public void setLinkUrlThumbnail(String linkUrlThumbnail) { + this.linkUrlThumbnail = linkUrlThumbnail; + } + + public String getLinkHost() { + return linkHost; + } + + public void setLinkHost(String linkHost) { + this.linkHost = linkHost; + } + + + public List getAttachments() { + return attachments; + } + + public void setAttachments(List attachments) { + this.attachments = attachments; + } + + @Override + public String toString() { + return "ClientFeed [key=" + key + ", type=" + type + ", userid=" + + userid + ", time=" + time + ", uri=" + uri + ", description=" + + description + ", fullName=" + fullName + ", email=" + email + + ", thumbnailURL=" + thumbnailURL + ", linkTitle=" + linkTitle + + ", linkDescription=" + linkDescription + + ", linkUrlThumbnail=" + linkUrlThumbnail + ", linkHost=" + + linkHost + ", attachments=" + attachments + "]"; + } +} diff --git a/target/classes/org/gcube/portal/databook/shared/ClientPost.class b/target/classes/org/gcube/portal/databook/shared/ClientPost.class new file mode 100644 index 0000000000000000000000000000000000000000..edf76fce6064f28382476bd5b0cb078a613ebe20 GIT binary patch literal 1730 zcmcgs?QR=I6g`vJj_ph~AyB{tO4HALZwsM7lNLfkDXo>FG>uf?2V;A1#@XyzyX#1K z6CMM8tSW)T1MpCYb7uoVLP#k;kfl9m?#!LJ_nv$G+wVXB3SbS7CNQS3l%)Nz-yL;q zI84&qL}Ab5rjsOxVRm3r+Y7fMXXE^p*G5F>Uy$vM_kX8XGgh(<(*yZ;b|NO!}^V>>#wuy0E)Oa0lFsQbR?G8h>>7MCG zn6vGqYodLVI$56@EBS$A5G&`6LFACvyQyXQlzKe>&+4Dwa;C%ieS8O;>imCt{TG=Q zUb3vM-BB!!y6-YajW**r$&IumC7NpwG8gAIO@^U4+Xx?JPmXOGnUnP<6fQRSxvo(~ zP1sG1iIOd7)JwLc(LhsnS2QL|Td1K+c3WerWbbPPCHp{Qx?~?}%#`e7jaN#xt}$D( zdm68n>=TXGa6v&O3eBg+Hm?-cbp cP1?tpsnq=f71?48+h5~zJjn0`9%lIR4_&Q#kN^Mx literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ClientPost.java b/target/classes/org/gcube/portal/databook/shared/ClientPost.java new file mode 100644 index 0000000..2fab59b --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ClientPost.java @@ -0,0 +1,51 @@ +package org.gcube.portal.databook.shared; + +import java.util.Date; + +import jsinterop.annotations.JsOverlay; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; +/** + * + * @author Massimiliano Assante, CNR-ISTI + * Uses JsInterop annotations to deserialize the object + */ +@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object") +public class ClientPost { + public String key; + public String type; + public String userid; + public Date time; + public String uri; + public String description; + public String fullName; + public String email; + public String thumbnailURL; + public String linkTitle; + public String linkDescription; + public String linkUrlThumbnail; + public String linkHost; + public ClientAttachment[] attachments; + @JsOverlay + public static ClientPost create(String key, String type, String userid, Date time, + String uri, String description, String fullName, String email, + String thumbnailURL, String linkTitle, String linkDescription, + String linkUrlThumbnail, String linkHost, ClientAttachment[] attachments) { + ClientPost o = new ClientPost(); + o.key = key; + o.type = type; + o.userid = userid; + o.time = time; + o.uri = uri; + o.description = description; + o.fullName = fullName; + o.email = email; + o.thumbnailURL = thumbnailURL; + o.linkTitle = linkTitle; + o.linkDescription = linkDescription; + o.linkUrlThumbnail = linkUrlThumbnail; + o.linkHost = linkHost; + o.attachments = attachments; + return o; + } +} diff --git a/target/classes/org/gcube/portal/databook/shared/Comment.class b/target/classes/org/gcube/portal/databook/shared/Comment.class new file mode 100644 index 0000000000000000000000000000000000000000..92439c66de272f2d6e2a485cb15551616c384c55 GIT binary patch literal 4064 zcmc&$ZEqA+6n>`N?rzIK>q3DF+Ll_oyM0-ZT2>2H-YPGpAT33TyiD6^nRdHdwzCK* zA}Aj;F;No}iHXLyFNldowj`PuKl{O7;qNd$=icdVJIosVb* zM%=uUo#{6aE-W(1l!1`z%rmq>2Nhf=lR99zwuDUE_LL5>uet`J(}hfC*pg_|y;PW= z$XZV3)X5=6I*SLV9EKR<+{;*tt~`#a#Npje)^P_2CY~5$x&65*yAIW8GSP^Q2I_~L ztUb(Zc79Z&jt%7|t<0E3j%49EL+&MK(Li$Oar;ODH{*{oujDBcuN0xW>-Fz(ViIGu zFwkP67Ik86GqFZn&zLZ=R(#KzSf_n)6ZP6knrP5gmx(8|)ng)t_43Ac6C1GBz(@Zp zw{hKoa?|9~Mma66%#MM`jO~u9q1g~mJlZS|Qb^JcdXp|`m+dv;FHQU!*(p8Mb8mFj5vb?>Y7gg~ zr$LD7vk{7qOF4OUXw?akS66##C)FXgM{@?cb6Q_SzBGnw&dkEqJFh>gM#x zh~TV&O@6)ES8y^@c0P)8eAUyrma`P6J#`qz1yO=Nu`Cl4m}E_BVZqK)oJiiEtN+n? z^3wN5AuzjIw6yJsVut&vS3^{|@HDp2GIbEP(g)g&^y>tFGBQeEpCm|j7SWvS zDxx*nT|`^5DO5yzvZMeR7kqjbcfoLdud>)hJ7v6;_tC zE26mV@VNa&ZqmZ^f8o{`6>?3r0qh1@{S{(7L?nmF?g-f(CA%TAJ4SZHoHDo)#LC0 z9X~R>3Nj914M6zQAd@Cg%w~ayekk$vmb~Z z2qYa0q}dO|A&}V$K;(!CkQV}hwEBU}2LgF97)Yxh$Ylb_R{$bsT!8SN;;)?4m7k`~ z52O$XWDf?smsfq7Hb0PS1aiFs5IH>pAvqfzMlpH8KfflkM9;Lm>0O6I+U+Kt#r%BtA575@RgrOx2-$hO6e))Nn&sF!UrCrrZ?KZLk@D&C1 zYYON$yz0J13%*-Xb6ZKfw&66dL<6t!jS#9D>S^;Yhgbb)W)wNS_AAEE#9n`h^DNuE zgp08${?Kj}ds^FVOSlx9({{V~=e6A-c23&~u`g?zY%azYwcWjhLhP!xQ { + + private String key; + private String userid; + private Date time; + private String feedid; + private String text; + private String fullName; + private String thumbnailURL; + private boolean isEdit; // false default + private Date lastEditTime; // null default + + /** + * + */ + public Comment() { + super(); + } + /** + * + * @param key + * @param userid + * @param time + * @param feedid + * @param text + * @param fullName + * @param thumbnailURL + */ + public Comment(String key, String userid, Date time, String feedid, + String text, String fullName, String thumbnailURL) { + super(); + this.key = key; + this.userid = userid; + this.time = time; + this.feedid = feedid; + this.text = text; + this.fullName = fullName; + this.thumbnailURL = thumbnailURL; + this.isEdit = false; + this.lastEditTime = null; + + } + + /** + * Constructor for edited comment + * @param key + * @param userid + * @param time + * @param feedid + * @param text + * @param fullName + * @param thumbnailURL + * @param isEdit + * @param editDate + */ + public Comment(String key, String userid, Date time, String feedid, + String text, String fullName, String thumbnailURL, boolean isEdit, Date editDate) { + super(); + this.key = key; + this.userid = userid; + this.time = time; + this.feedid = feedid; + this.text = text; + this.fullName = fullName; + this.thumbnailURL = thumbnailURL; + this.isEdit = isEdit; + this.lastEditTime = editDate; + } + + /** + * + * @return the text + */ + public String getText() { + return text; + } + /** + * + * @param text text to add as string + */ + public void setText(String text) { + this.text = text; + } + /** + * + * @return the uuid + */ + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getUserid() { + return userid; + } + + public void setUserid(String userid) { + this.userid = userid; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getFeedid() { + return feedid; + } + + public void setFeedid(String feedid) { + this.feedid = feedid; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public boolean isEdit() { + return isEdit; + } + public void setEdit(boolean isEdit) { + this.isEdit = isEdit; + } + public Date getLastEditTime() { + return lastEditTime; + } + public void setLastEditTime(Date lastEditTime) { + this.lastEditTime = lastEditTime; + } + public int compareTo(Comment toCompare) { + if (this.time.after(toCompare.getTime())) + return 1; + if (this.time.before(toCompare.getTime())) + return -1; + return 0; + } + + @Override + public String toString() { + return "Comment [key=" + key + ", userid=" + userid + ", time=" + time + + ", feedid=" + feedid + ", text=" + text + ", fullName=" + + fullName + ", thumbnailURL=" + thumbnailURL + ", isEdit=" + + isEdit + ", lastEditTime=" + lastEditTime + "]"; + } +} diff --git a/target/classes/org/gcube/portal/databook/shared/EnhancedFeed.class b/target/classes/org/gcube/portal/databook/shared/EnhancedFeed.class new file mode 100644 index 0000000000000000000000000000000000000000..956015c4483d6a465175c1efb4e018d65390cbde GIT binary patch literal 3568 zcmbuBZBr9h6vxknJP}fm@Swzqi_)6Jz}Bj@8lfOhrHzWBv|?>%N!G9$5@xgMjD6GZ z(9h8qI#Y0_o#_YYhwAiy?p-!Z*bGm@uzUCJ-v9ZXhkI`R{qL`Ti0Bsm9HlNnlXbhI zS4z!IQ{SoEj#1UihGT5j>u>eOmSLM^eX+J>)JkS~$u!GR3JE&*#`wk1t46J&Ki+&} zmYgU>1P#eqtFEt^wq;bUUyaSGDJb+B%LH939%+a53xdK`>n*Pk8-k)%<9Wlh8-ik` z`u4V2b1)n(N=r@0s_JvLZM-X54F?N*)~rg+aGEx(&INsQ|7eDJWu-6!yWnXbDoG4joi0tmNO%$JCj{Ubmr@2Gfv$!lAt6F3hFOfHSG$yJi45q9*Xm5JVCt_N0g5* z78Jb#M_~JG8YjxB^61k9CFm1DBL@TfZf8HZ>t{nMboBMZ*@REzYY@aS1P+v|idQZ{ z=Qv)y71MF|2TJdJCL3e|B{m=Y<`~8g?7oKI+J#J@F)pBmz*i@-#xhZO$AvE_3;yFa zt0*Yds@!pND~(x=qUv&J1L$)x$hZ@s3^tycaa&&>$XaPZ=$B3%;FgSRMtv~bnu7B3 zX=B+^fw1Iv>T8Z|)haj`_HpHjp=JwFnnMk>4iYu}plMahrX8bsL4*FzrM-NO+)T%5 zmKM2FF5wt(S^cWnb^hX;1g+4wf+EJwj#)!SC;gwQBdg$6uWz+$ybz-z;-A;#IV4R! zV!_94I<6y~br|IduY4*fjjXB)4m9{oP&}`>huw6HPyoGoZU4x_#1De{@|xkDB@N7> zZp14#@?(N#=xa!<)th$7T(bDw9q@;5iUUpKXx-iT596Rdb z)`_yv%fb3}(B?rq3A!oxpiANzrRfoC9x;2U@~C;lnoA4{Sr%c*J_0hHQS9p703sn^ zGw*pZDZS7!%ee{X{-lZb7<9?NM&#rTiPT;!Q$XEM+2>MZ70+xk!kO}=N8xf3Zc8Nv z7V(^mNPOW7IL~lJ3%WsH;L0WGM@+XP-U&p!iC@!d@r)lW-Kt=Pb`NNU4rsg`8RRy7 z82~c&M_a6>13~W4SBF3@Vn4Nm%mQSt0|=*`L3#s0w04mBK#;q^Aih1VBC-UK comments; + private ArrayList attachments; + + + public EnhancedFeed() { + super(); + } + public EnhancedFeed(Feed feed, boolean liked, boolean isUsers) { + super(); + this.feed = feed; + this.liked = liked; + this.isUsers = isUsers; + } + + public EnhancedFeed(Feed feed, boolean liked, boolean isUsers, ArrayList comments) { + super(); + this.isUsers = isUsers; + this.feed = feed; + this.liked = liked; + this.comments = comments; + } + + + public EnhancedFeed(Feed feed, boolean liked, boolean isUsers, + ArrayList comments, ArrayList attachments) { + super(); + this.feed = feed; + this.liked = liked; + this.isUsers = isUsers; + this.comments = comments; + this.attachments = attachments; + } + public ArrayList getComments() { + return comments; + } + public void setComments(ArrayList comments) { + this.comments = comments; + } + public Feed getFeed() { + return feed; + } + public void setFeed(Feed feed) { + this.feed = feed; + } + public boolean isLiked() { + return liked; + } + public void setLiked(boolean liked) { + this.liked = liked; + } + public boolean isUsers() { + return isUsers; + } + public void setUsers(boolean isUsers) { + this.isUsers = isUsers; + } + public ArrayList getAttachments() { + return attachments; + } + public void setAttachments(ArrayList attachments) { + this.attachments = attachments; + } + @Override + public String toString() { + return "EnhancedFeed [feed=" + feed + ", liked=" + liked + ", isUsers=" + + isUsers + ", comments=" + comments + ", attachments=" + + attachments + "]"; + } + +} diff --git a/target/classes/org/gcube/portal/databook/shared/Feed.class b/target/classes/org/gcube/portal/databook/shared/Feed.class new file mode 100644 index 0000000000000000000000000000000000000000..0fb64a5f96bcb292e1210e1350265a411d30e69a GIT binary patch literal 8094 zcmeI0ZE##w8ONWKm)%Wro21*OaBYED?ULLiUD8lWNzZ5MRI1&SH?b%xRMevQHp2&<@q^CjjGgfV&N%A-Ip^kX_U5b& z>PIFsd!BplIp_Y)^E~IA|H+wuKJ_dST~5CaQ;DE8>FjuXd~|xmj%U(YH<65wCEUbF zIz17eI+)1XWASd=9t%^MpxQ%;!-;q@F*zRJJ#xq%b;A@Av|QFY>G*)1brMPEhQvtH z4pU_AjcmUyoysJ#{6H#82zGuzT*b|sb48iU?UtI?y+nY4Go1$K5&#U3*alYA_TwUBw{WzwSBoHxe`V!Nmz7o_xm*Q;^3 zf&?`iR6&(&tu?5M47M&aXo;#@XHYfOaNXqw)vCHH3|gwJD-DV&>nekmDQlBK%c+ig zY&K|xs(YJ37bt71K^IbGgtjB0F5^bs2AS&BPJ`a0tg8)LrK~=KRw`?kK^G}&k3kpH zB|>z+kpjF&zMfoMkU0Aqhbs|;0bZ?^5EE~>^nZ5gV%Fk5_??q~*r0l(GKI!%x0jEr z~YN=E0Vl;2yy%U_kRmw7YFzvZDL7C9Oo>_xhUpUC~yaq1| zYnGr5^p1bXFF}j>&ph$IxpSW<;Xm-`@SZ;$PHDU@tTAM7Un>~0zyBEZ-WGT|>a{7T ztbh)IB(n!0L##zOPaf}$J-jJ>%%B8~RML%fbC_-tR9$#N8*~fZ3jLEf;M!S1nmpRa zeQ!7D4sI73u@9uPSRfT{8g61HK}!bQ#OOqSBIC&r&S(f0PXlqJ@=r^hsm`D#g6M%N z;)ySKRn~wtE(pE)gPMukFQ|;TX|b6(1b6DK(@t{C&PM3d$Vhfl{q@kd9hG#9 zKFgao=6Z}CGU)U41XRVd~-dEVkwzX^BkhBYUX7*>c1}mxFySHRQy0T42Wpy)E}`^Ul6nk3GyF8aYhah z(AyaJB?zbe9PFPObU$4ysNhJL3yxesFB|k>`UvJUke<$t+AQ0V{+v8(Ilb^=yPe6} z5c#a{D+ZkL$%H%2>tcK!m^Y-V3EaQh=e1LdiZ%VF#hoMVo7<7NxH(V>l~Wk{v4oW< zE{!FuLuCmSDobckSwexz68ck?P@l4d_LL=*r!1j6WeL?OOK476LTbtqLQ|Fym$HQ1 zlqDo4N@9U2OPtOqTR@5141V8&r#6%VWw~{V-g*K?3B~YRiIS*+%BYbpg=MHlsA1ZeHPKFLr5@TqS5pV|qD3E``e`@qq9OcVPkXRAUqj=x zmy$FfCwyE@%9}8zC!@)pO38S#ds2L_K*ZVNn3hS4qgpO4j%!F-9NDn6IJOaKada!B z#qs4xrTAWf(b?h{bJnEz%7E{%#c{2c7Du*5hT$3&26_#=OYtsdH8r=GWoEe&M3RW8?aaAmwWGhG?4sI+(|T85atov!urH;z*6Lno=}aWqoq(d?3^=b{r}BupD89YUMjG>B2 z=5;OzO=}S3G(es!0>V2ggV@mtw%b7Ab-$;Wb_{C2!i|(Ab%TP{L8i1Iok5VlX+c~)NM{h_HGurR2nY)p2AS4^bOk~Fp#?dt z2k8oe{ENzQc(71ixW)51#USt1g6s%@h!QQx`}80?0wAIsAfX~4d`vRP5iQ7uAV@?D za)TaZLlC42AVv`oR%8tFel19E5Tr&6@&P?aZxAF3kYzIcZs-rXVYSu`cj?{G zA9TYSxFI$VDdZ!Cq*P-!+zlbRa9`ieGo2^Pg#K!H57evboZr`17Th_cEECNDX(j2VL1cZeugW#VN_~rZVHUyi6>ba-s*mcndPtj+P z5lE2FMZbt2*e$d4aP$#n$GQHi%5LTQN0r^i^)t#|&-OQzy@Bn=mA#SeZz;Q-`<_&G z2iMOkdkfo7D7%yGrmlQN&Ce{nif~lQPGZnux-MBo;v8P*i5gAE%X<(%l`x6oJzLZ sPOP+_DTiVeDDhrlHJv6gOJ@VoMKd0N^?fP*Tw1@NS5OlDQa=6a-*mwplmGw# literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/Feed.java b/target/classes/org/gcube/portal/databook/shared/Feed.java new file mode 100644 index 0000000..514a0db --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/Feed.java @@ -0,0 +1,322 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.Date; + +/** + * + * @author Massimiliano Assante, ISTI-CNR + * @deprecated use org.gcube.portal.databook.shared.Post instead + */ +@SuppressWarnings("serial") +public class Feed implements Serializable, Comparable { + + private String key; + private FeedType type; + private String entityId; + private Date time; + private String vreid; + private String uri; + private String uriThumbnail; + private String description; + private PrivacyLevel privacy; + private String fullName; + private String email; + private String thumbnailURL; + private String commentsNo; + private String likesNo; + private String linkTitle; + private String linkDescription; + private String linkHost; + boolean applicationFeed; + /** + * this boolean indicates that the attachments to the post are > 1 + */ + boolean multiFileUpload; + /** + * default constructor + */ + public Feed() { + super(); + } + /** + * To use ONLY for USER Feeds + * + * + * @param key a UUID + * @param type an instance of FeedType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + * @param linkHost option to be used when posting linkgs + */ + public Feed(String key, FeedType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String linkTitle, String linkDescription, String linkHost) { + this.key = key; + this.type = type; + this.entityId = entityId; + this.time = time; + this.vreid = vreid; + this.uri = uri; + this.uriThumbnail = uriThumbnail; + this.description = description; + this.privacy = privacy; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.commentsNo = "0"; + this.likesNo = "0"; + this.linkDescription = linkDescription; + this.linkTitle = linkTitle; + this.linkHost = linkHost; + this.applicationFeed = false; + } + /** + * To use for USER and ApplicationProfile Feeds + * + * @param key a UUID + * @param type an instance of FeedType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + * @param applicationFeed tell if this is an application feed or a user feed + */ + public Feed(String key, FeedType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String linkTitle, String linkDescription, String linkHost, boolean applicationFeed) { + this(key, type, entityId, time, vreid, uri, uriThumbnail, description, privacy, fullName, email, thumbnailURL, linkTitle, linkDescription, linkHost); + this.applicationFeed = applicationFeed; + } + + + /** + * for serialization purposes + * @param key a UUID + * @param type an instance of FeedType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + */ + public Feed(String key, FeedType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String commentsNo, + String likesNo, String linkTitle, String linkDescription, String linkHost, boolean applicationFeed, boolean multiFileUpload) { + super(); + this.key = key; + this.type = type; + this.entityId = entityId; + this.time = time; + this.vreid = vreid; + this.uri = uri; + this.uriThumbnail = uriThumbnail; + this.description = description; + this.privacy = privacy; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.commentsNo = commentsNo; + this.likesNo = likesNo; + this.linkDescription = linkDescription; + this.linkTitle = linkTitle; + this.linkHost = linkHost; + this.applicationFeed = applicationFeed; + this.multiFileUpload = multiFileUpload; + } + /** + * + * @return the key + */ + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public FeedType getType() { + return type; + } + + public void setType(FeedType type) { + this.type = type; + } + /** + * + * @return the User or the App id + */ + public String getEntityId() { + return entityId; + } + /** + * set the User or the App id + * @param entityId the UserId or the AppId id + */ + public void setEntityId(String entityId) { + this.entityId = entityId; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getVreid() { + return vreid; + } + + public void setVreid(String vreid) { + this.vreid = vreid; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public PrivacyLevel getPrivacy() { + return privacy; + } + + public void setPrivacy(PrivacyLevel privacy) { + this.privacy = privacy; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String getCommentsNo() { + return commentsNo; + } + public void setCommentsNo(String commentsNo) { + this.commentsNo = commentsNo; + } + public String getLikesNo() { + return likesNo; + } + public void setLikesNo(String likesNo) { + this.likesNo = likesNo; + } + public String getUriThumbnail() { + return uriThumbnail; + } + public void setUriThumbnail(String uriThumbnail) { + this.uriThumbnail = uriThumbnail; + } + + public String getLinkTitle() { + return linkTitle; + } + public void setLinkTitle(String linkTitle) { + this.linkTitle = linkTitle; + } + public String getLinkDescription() { + return linkDescription; + } + public void setLinkDescription(String linkDescription) { + this.linkDescription = linkDescription; + } + public int compareTo(Feed toCompare) { + if (this.time.after(toCompare.getTime())) + return 1; + if (this.time.before(toCompare.getTime())) + return -1; + return 0; + } + public String getLinkHost() { + return linkHost; + } + public void setLinkHost(String linkHost) { + this.linkHost = linkHost; + } + + public boolean isApplicationFeed() { + return applicationFeed; + } + public void setApplicationFeed(boolean applicationFeed) { + this.applicationFeed = applicationFeed; + } + public boolean isMultiFileUpload() { + return multiFileUpload; + } + public void setMultiFileUpload(boolean multiFileUpload) { + this.multiFileUpload = multiFileUpload; + } + @Override + public String toString() { + return "Feed [key=" + key + ", type=" + type + ", entityId=" + entityId + + ", time=" + time + ", vreid=" + vreid + ", uri=" + uri + + ", uriThumbnail=" + uriThumbnail + ", description=" + + description + ", privacy=" + privacy + ", fullName=" + + fullName + ", email=" + email + ", thumbnailURL=" + + thumbnailURL + ", commentsNo=" + commentsNo + ", likesNo=" + + likesNo + ", linkTitle=" + linkTitle + ", linkDescription=" + + linkDescription + ", linkHost=" + linkHost + + ", applicationFeed=" + applicationFeed + + ", multiFileUpload=" + multiFileUpload + "]"; + } + +} diff --git a/target/classes/org/gcube/portal/databook/shared/FeedType.class b/target/classes/org/gcube/portal/databook/shared/FeedType.class new file mode 100644 index 0000000000000000000000000000000000000000..67e2772e5843ae26c651bbbc4f47fdeca248f081 GIT binary patch literal 1377 zcmb7DT~ks~6kSI??gg(&WSU=PX~u_nv(hr~0}+!%Xu3dir(P~_LkxkrT%6%w^iv8S zbZT;X=&2vow9gTfmu7;8yU*I}v(8@otn=&l*K+_*5tlH)5Ug8ewOni!Otn$BY@@1{ z4BIHw>mSwTfnk{?b;mSI*>=N};AFUVXdD}A)u@%#M6Gqi;Cz)yrWwMi|K^D>xU}8a zn*@XOI=7WdYP*!lzD*>u44!xyUN4z4TwXAYD7cAH26wbuG8#x-3D#_@QY%N2 z!MulRZz*uWEkoj9Qh~&Q%)xC1G6x>4gI$q`^L@G^y=lquMfQu^0&UGZinn zVMW3+gRe(zyJ?$83ZCIPU5jB^M!Q&Vw5iqJnPduwX3>r$d&YE`qB+qGi zWfl$FERkTXQmz?x%c8=y9&Sz)?W61U$mSAVs)JsfygAMt15hNhh)6yWkt`x2xkE%U zhKS?|z&F7iK@3jv)i8X-cb(8r!uI|Y~!V9F)Hv;cS90?Y_- zPZD5Ofcvrl^8y5X7j;3O^qtrp9gJzZvx5mucXcqW>Fy3@G+pXoR@3DU<~7|%si1a( z@E7W701xRq!Mi8>$H?`2q#;czbn5**=~xt1ypmpASJ4v9iBC!jg{MxTUJ<#efCeZw zDPk?*QI~uPkGtDfXuN#;Xa`|^&k;J;qrCZj$K)BFEPNIR^0qG6=#_{JZ*Ubax*Q>D dh@a*4v(OnLKfwOI&w+Kpuz^jAAemgw)*rzsC(i%? literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/FeedType.java b/target/classes/org/gcube/portal/databook/shared/FeedType.java new file mode 100644 index 0000000..71fe688 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/FeedType.java @@ -0,0 +1,19 @@ +package org.gcube.portal.databook.shared; + +/** + * @author Massimiliano Assante ISTI-CNR + * @deprecated use PostType + * @version 1.2 October 2012 + */ +public enum FeedType { + JOIN, SHARE, PUBLISH, TWEET, CONNECTED, + /** + * Special case used when accounting + */ + ACCOUNTING, + /** + * Special case used when a Feed is removed + */ + DISABLED; +} + diff --git a/target/classes/org/gcube/portal/databook/shared/ImageType.class b/target/classes/org/gcube/portal/databook/shared/ImageType.class new file mode 100644 index 0000000000000000000000000000000000000000..6671def3dafee9191f22639495b40c522e801b33 GIT binary patch literal 1275 zcmb7@ZBNrs6vzLUZtGSm%%M{r6h)A2JX93$VRJzd$aD;n!ji^UccYGCx00?SS^O}5 z1syLW8i}v{P{wnw6ZXc$^+ivAxA*+-Ij8^r{Pp!5z%ueG1{gA)Uo&deR>d}sJwM>C zaliv!@x1p&^N{=Yfl;XQn!VRPwpD}}hK~3NH(cJR85@mOok4lMyTveH{C}M+C2bWp z>AqW{)X-jGQ^G58f4RNOFt}0L-<~eNDDH2V3=41j6OZPquG4UWJjtcfWjbNqJFue& zYhW1BaShiQBDwCCWU6@Ck{S3;qn0hC%Q4z}Lq`~qC{zJsI#dBs0k?ES1;hm0(Ge4% z3Am?26EG;?zK%ge#8XO#jw=kqMWC_rLX!-Oq-=imzbN!T>&#o=ew^Zo&QP)O=Hvo!c3mM4~GLji& zBp=8~769U7!T^*RBIgWYm~`SqABn~F;TxEhxT<_X;uJ{8ms`k)G^e)_S94 z&aIrNa$6ZcgE9X}9w^HAqehODD?(!ht6hx@6(r8m5-f9u$3MXSoi~7IQXz|+jL&}q DS2Gp~ literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ImageType.java b/target/classes/org/gcube/portal/databook/shared/ImageType.java new file mode 100644 index 0000000..15f2719 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ImageType.java @@ -0,0 +1,5 @@ +package org.gcube.portal.databook.shared; + +public enum ImageType { + JPG, GIF, PNG, TIFF, PDF, BMP; +} diff --git a/target/classes/org/gcube/portal/databook/shared/Invite.class b/target/classes/org/gcube/portal/databook/shared/Invite.class new file mode 100644 index 0000000000000000000000000000000000000000..a0300ca9f30c2b6060c739b3231ad291c5b012c0 GIT binary patch literal 3104 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/JSON.java b/target/classes/org/gcube/portal/databook/shared/JSON.java new file mode 100644 index 0000000..7a660f0 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/JSON.java @@ -0,0 +1,10 @@ +package org.gcube.portal.databook.shared; + +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class JSON { + public static native String stringify(Object o); + public static native O parse(String json); +} diff --git a/target/classes/org/gcube/portal/databook/shared/JobStatusType.class b/target/classes/org/gcube/portal/databook/shared/JobStatusType.class new file mode 100644 index 0000000000000000000000000000000000000000..da43e571575dfa6064de09c6eb35b3e1321d55d5 GIT binary patch literal 1667 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 Hi2m|Fmeyxt literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/NotificationType.java b/target/classes/org/gcube/portal/databook/shared/NotificationType.java new file mode 100644 index 0000000..36ddfa9 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/NotificationType.java @@ -0,0 +1,181 @@ +package org.gcube.portal.databook.shared; + + + +/** + * @author Massimiliano Assante ISTI-CNR + * + * TODO: Buggy if NotificationType for WP_* are refactored see DBCassandraAstyanaxImpl#getUserNotificationPreferences(String userid) + * introduced due to urgent matters + */ +public enum NotificationType { + /** + * use to notify a user he got a Tabular Resource shared + */ + TDM_TAB_RESOURCE_SHARE, + /** + * use to notify a user he got a TDM Rule shared + */ + TDM_RULE_SHARE, + /** + * use to notify a user he got a TDM Templated shared + */ + TDM_TEMPLATE_SHARE, + /** + * use to notify a user he got a workspace folder shared + */ + WP_FOLDER_SHARE, + /** + * use to notify a user that a user in the share unshared + */ + WP_FOLDER_UNSHARE, + /** + * use to notify a user that he got upgraded to administrator of a shared folder + */ + WP_ADMIN_UPGRADE, + /** + * use to notify a user that he got downgraded from administrator of a shared folder + */ + WP_ADMIN_DOWNGRADE, + /** + * use to notify a user that a new user was added in on of his workspace shared folder + */ + WP_FOLDER_ADDEDUSER, + /** + * use to notify a user that an existing user was removed from one of his workspace shared folder + */ + WP_FOLDER_REMOVEDUSER, + /** + * use to notify a user he got a workspace folder renamed + */ + WP_FOLDER_RENAMED, + /** + * use to notify a user he got a workspace item deleted from one of his workspace shared folder + */ + WP_ITEM_DELETE, + /** + * use to notify a user he got a workspace item updated from one of his workspace shared folder + */ + WP_ITEM_UPDATED, + /** + * use to notify a user he got a workspace item renamed from one of his workspace shared folder + */ + WP_ITEM_RENAMED, + /** + * use to notify a user he got a workspace item new in some of his workspace shared folder + */ + WP_ITEM_NEW, + /** + * use to notify a user he got one of his feed commented + */ + OWN_COMMENT, + /** + * use to notify a user that commented on a feed (Not his) that someone commented too + */ + COMMENT, + /** + * use to notify a user that he got mentioned in one post + */ + MENTION, + /** + * use to notify a user he got one of his feed liked + */ + LIKE, + /** + * use to notify a user he got a message + */ + MESSAGE, + /** + * use to notify every user of a VRE/Group that the post was made + */ + POST_ALERT, + /** + * use to notify a user that someone in his VRE created a new Event in the Calendar + */ + CALENDAR_ADDED_EVENT, + /** + * use to notify a user that someone in his VRE updated an Event in the Calendar + */ + CALENDAR_UPDATED_EVENT, + /** + * use to notify a user that someone in his VRE deleted an Event in the Calendar + */ + CALENDAR_DELETED_EVENT, + /** + * use to notify a user he got a connections request + */ + REQUEST_CONNECTION, + /** + * use to notify a user he got a job completed ok + */ + JOB_COMPLETED_OK, + /** + * use to notify a user he got a job completed not ok + */ + JOB_COMPLETED_NOK, + /** + * use to notify a document workflow owner that someone + * has edited a document involved in a worflow he created + */ + @Deprecated + DOCUMENT_WORKFLOW_EDIT, + /** + * use to notify a document workflow owner that someone + * has viewed a document involved in a worflow he created + */ + @Deprecated + DOCUMENT_WORKFLOW_VIEW, + /** + * use to notify a document workflow user (user that in the same document workflow) + * that forwarded to a step where he is requested to do a task + */ + @Deprecated + DOCUMENT_WORKFLOW_STEP_REQUEST_TASK, + /** + * use to notify a document workflow user that he was involved into a new Document Workflow + * and he is requested to do a task + */ + @Deprecated + DOCUMENT_WORKFLOW_FIRST_STEP_REQUEST_INVOLVMENT, + /** + * use to notify a document workflow owner that a user performed a forward action to another step a document worflow he created + */ + @Deprecated + DOCUMENT_WORKFLOW_USER_FORWARD_TO_OWNER, + /** + * use to notify a document workflow owner that someone + * forwarded and the workflow moved to another step a document worflow he created + */ + @Deprecated + DOCUMENT_WORKFLOW_FORWARD_STEP_COMPLETED_OWNER, + /** + * use to notify a document workflow peer (user that in the same step has your same role) + * that someone performed a forward action to another step in a document worflow he is involved into + */ + @Deprecated + DOCUMENT_WORKFLOW_STEP_FORWARD_PEER, + /** + * catalogue, use to notify someone submits an item for consideration + */ + CAT_ITEM_SUBMITTED, + /** + * catalogue, use to notify someone rejected a submitted item + */ + CAT_ITEM_REJECTED, + /** + * catalogue, use to notify someone published an item + */ + CAT_ITEM_PUBLISHED, + /** + * catalogue, use to notify someone updated an item + */ + CAT_ITEM_UPDATED, + /** + * catalogue, use to notify someone removed an item + */ + CAT_ITEM_DELETE, + /** + * generic notification + */ + GENERIC; +} diff --git a/target/classes/org/gcube/portal/databook/shared/Post.class b/target/classes/org/gcube/portal/databook/shared/Post.class new file mode 100644 index 0000000000000000000000000000000000000000..d3fc283e8d07ff02ed53c92a0780487d57c8f15e GIT binary patch literal 8075 zcmeI0dvIJ;9mjt+kKIjj^XRrITw6-4c1dnFUD8lW*(Nn@lQtx2OY;zlRX53PdYj#B z+}y1eANb&n1w^3W1GOkBM5WqId5J|)p`sQ=M`!p$XZ%BFbjHs32hKR^_jk_C-QAnB z64XDL%-r+4=bm%+bAG?yIp=$F_McBZOGKB^uY**k(YkbIGB!D$9kXIH>5P*|#wHR@ zVl17Wip?HMWUPtU-t?>!qza814kwNzV#&nxWNgpaVQU<<0gYCOT00#ZvNCoeX#gs!@0#KiZI!v8N~F8dW$)XV9W`U`bHJXpBxFYud4$ zqkR+H-%g=_gB&~S*vZ(Agu{(0k7O(xEy}YQTO%FM;X~Qf*mS~9YE&~}&5md68OKgf zYZRQx*hdoMV2mw+L$)2Tj#x=%Ihai*cPAL4(n^WJb!Xv+M)nP8R6U+fr9eEpJB^=8 z+EbRWs*?8f)UfTagX-DdQHT`cnq7zkJ|<>nlJ}lKS!i<|+M&X(5=?SZv%4wZWZ>6>9FHn@* z%V-s86xFGUs@YnvQw`~CU8+;9tlOYd9o2K)WjZy;y32K1Cao)U3QOxsot8^$i%u)3 zk$ZIMv{Kf+L#GR*wN0lBsX9bEkWiO$qh6g1`DvFX?Mre_;eL#h6eD^AY*>nq3i~hksnI!B2S0i zHbs?H&>@gy)-Ysv4KWr!UYKF;|E;YZ~gTO|@Mt+F;zV;~_eMl^Jbvu#t$7zs%!(#W#%9 z~A3xh3%y#Do-Nv z(WZ&KPDR~!;Dl(CE1>b76F;~hicxV|{DzRmczaTe>l6rNR6dRHN1KqI?g~QHcg3)- zSjPMJAmO7;EQ*C>M$L1GwyY`0a@7Ao0B}o|sJXy_Bs!l^%Ir@o-kY9z>i2*p`3 zfKP8@;Flnr4sfu4rqlg&jYdUB!a{Jw0(x1e8|b5$(@;8_8Mj!rBmFsf)^mEn9h_6P--YE&C~SulQ7CCf@d{KqGqa~7PQX#_*_xwPGn%6|vn@w4)2PT%yJ=MBsKYb@IofC%!5nQejZls@n?_ZR;-*oZqfXPP z$W1 z>QB=?v$3Jbe|3WYFnl!yUnRxd=j2G<+#}xHBi`I2-rOVJ+#`IA5_6C6HA>7q!q+G< z_XuC3#M~o%jS_Q@@HGm5;P&Po@#Y@!<{t6p9^t!^SU(Yw*A2o8!)`LpAsIOzoc~`k za_aSnG(d1(=0t8Vslo`&x?)Y z#m4bs<9M-gyx2HiY#c8(ju#upi;d&O#_?j~c(HN3*f@N*6?y6K-B#qKBjUw-n?7J9nWqFUWw{ zfAWElyVwb&zh#RC}bu5Ap&)UMvB^n;L^mDnT~-L0(dV98!a9^n;uO$jc=_ zcu!>zTM4q+5Auo<9~@)|(?UIK)8qAU%GNe<(qYs6l%CApfFD93CuG z7jN-=PBF;)l^{EPAX=Fc339y}WRoAH1|WI~ z5LRRi@43Om|Kv>!`$cL36eSVNeCCEqAAboz23jt!30AXd# zAh=ZG$%o#ID=F5Rr>MPko<25DpLmceE9Ua=x8c2Pu6z!y%f+Q>C6)tetEf&}O%2*b zv_@M)P1?l;zq!_v9&4fhTJT%P(7S@l8u+ZcQ|X35zZ=#n-Ef!M4TF9+tb-dO1xNu8 zDIla8yWwsK(Z&1v9-e7|EYs9i!+W4!W#|09zN+ZXA!L~r1xQ;75WcZ8$h}IC5kE*w z>5==?AO%8Qf@}atM+p!XstkhvN8ri#-R%fA3)S;a)A4J=51yvaA|sF>pAUZt57=$< z^l}-pKYhrM-#m$ECfQ?Qcsv&V5fwyOZnZrM;EyC#2oY z_EXaCVfz_r?_~Q~Y4@{zM%sOBe_z^zY(FpUJ@fRV@QczOVf!br=jo^UG+fVjRPAzV z);7_Ab_E^KHd9u+l8$L{{7-EQ{@K(?=d><*RohB`LA(4v5YEeFYv{&G`?+)|R)G}n eRc7lM(&p)$FS=;P1F*g?qhE;UFX { + + private String key; + private PostType type; + private String entityId; + private Date time; + private String vreid; + private String uri; + private String uriThumbnail; + private String description; + private PrivacyLevel privacy; + private String fullName; + private String email; + private String thumbnailURL; + private String commentsNo; + private String likesNo; + private String linkTitle; + private String linkDescription; + private String linkHost; + boolean applicationFeed; + /** + * this boolean indicates that the attachments to the post are > 1 + */ + boolean multiFileUpload; + /** + * default constructor + */ + public Post() { + super(); + } + /** + * To use ONLY for USER Feeds + * + * + * @param key a UUID + * @param type an instance of PostType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + * @param linkHost option to be used when posting linkgs + */ + public Post(String key, PostType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String linkTitle, String linkDescription, String linkHost) { + this.key = key; + this.type = type; + this.entityId = entityId; + this.time = time; + this.vreid = vreid; + this.uri = uri; + this.uriThumbnail = uriThumbnail; + this.description = description; + this.privacy = privacy; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.commentsNo = "0"; + this.likesNo = "0"; + this.linkDescription = linkDescription; + this.linkTitle = linkTitle; + this.linkHost = linkHost; + this.applicationFeed = false; + } + /** + * To use for USER and ApplicationProfile Feeds + * + * @param key a UUID + * @param type an instance of FeedType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + * @param applicationFeed tell if this is an application feed or a user feed + */ + public Post(String key, PostType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String linkTitle, String linkDescription, String linkHost, boolean applicationFeed) { + this(key, type, entityId, time, vreid, uri, uriThumbnail, description, privacy, fullName, email, thumbnailURL, linkTitle, linkDescription, linkHost); + this.applicationFeed = applicationFeed; + } + + + /** + * for serialization purposes + * @param key a UUID + * @param type an instance of PostType + * @param entityId the user or the app unique indentifier + * @param time when + * @param vreid a unique vre id + * @param uri optional uri + * @param uriThumbnail the thumbnail for the link posted + * @param description optional description + * @param privacy the privacy level of PrivacyLevel + * @param fullName + * @param email + * @param thumbnailURL this is the user thumbnail url + * @param linkTitle optional to be used when posting links + * @param linkDescription optional to be used when posting links + */ + public Post(String key, PostType type, String entityId, Date time, + String vreid, String uri, String uriThumbnail, String description, PrivacyLevel privacy, + String fullName, String email, String thumbnailURL, String commentsNo, + String likesNo, String linkTitle, String linkDescription, String linkHost, boolean applicationFeed, boolean multiFileUpload) { + super(); + this.key = key; + this.type = type; + this.entityId = entityId; + this.time = time; + this.vreid = vreid; + this.uri = uri; + this.uriThumbnail = uriThumbnail; + this.description = description; + this.privacy = privacy; + this.fullName = fullName; + this.email = email; + this.thumbnailURL = thumbnailURL; + this.commentsNo = commentsNo; + this.likesNo = likesNo; + this.linkDescription = linkDescription; + this.linkTitle = linkTitle; + this.linkHost = linkHost; + this.applicationFeed = applicationFeed; + this.multiFileUpload = multiFileUpload; + } + /** + * + * @return post id + */ + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public PostType getType() { + return type; + } + + public void setType(PostType type) { + this.type = type; + } + /** + * + * @return the User or the App id + */ + public String getEntityId() { + return entityId; + } + /** + * set the User or the App id + * @param entityId the UserId or the AppId id + */ + public void setEntityId(String entityId) { + this.entityId = entityId; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public String getVreid() { + return vreid; + } + + public void setVreid(String vreid) { + this.vreid = vreid; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public PrivacyLevel getPrivacy() { + return privacy; + } + + public void setPrivacy(PrivacyLevel privacy) { + this.privacy = privacy; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getThumbnailURL() { + return thumbnailURL; + } + + public void setThumbnailURL(String thumbnailURL) { + this.thumbnailURL = thumbnailURL; + } + + public String getCommentsNo() { + return commentsNo; + } + public void setCommentsNo(String commentsNo) { + this.commentsNo = commentsNo; + } + public String getLikesNo() { + return likesNo; + } + public void setLikesNo(String likesNo) { + this.likesNo = likesNo; + } + public String getUriThumbnail() { + return uriThumbnail; + } + public void setUriThumbnail(String uriThumbnail) { + this.uriThumbnail = uriThumbnail; + } + + public String getLinkTitle() { + return linkTitle; + } + public void setLinkTitle(String linkTitle) { + this.linkTitle = linkTitle; + } + public String getLinkDescription() { + return linkDescription; + } + public void setLinkDescription(String linkDescription) { + this.linkDescription = linkDescription; + } + public int compareTo(Post toCompare) { + if (this.time.after(toCompare.getTime())) + return 1; + if (this.time.before(toCompare.getTime())) + return -1; + return 0; + } + public String getLinkHost() { + return linkHost; + } + public void setLinkHost(String linkHost) { + this.linkHost = linkHost; + } + + public boolean isApplicationFeed() { + return applicationFeed; + } + public void setApplicationFeed(boolean applicationFeed) { + this.applicationFeed = applicationFeed; + } + public boolean isMultiFileUpload() { + return multiFileUpload; + } + public void setMultiFileUpload(boolean multiFileUpload) { + this.multiFileUpload = multiFileUpload; + } + @Override + public String toString() { + return "Post [key=" + key + ", type=" + type + ", entityId=" + entityId + + ", time=" + time + ", vreid=" + vreid + ", uri=" + uri + + ", uriThumbnail=" + uriThumbnail + ", description=" + + description + ", privacy=" + privacy + ", fullName=" + + fullName + ", email=" + email + ", thumbnailURL=" + + thumbnailURL + ", commentsNo=" + commentsNo + ", likesNo=" + + likesNo + ", linkTitle=" + linkTitle + ", linkDescription=" + + linkDescription + ", linkHost=" + linkHost + + ", applicationFeed=" + applicationFeed + + ", multiFileUpload=" + multiFileUpload + "]"; + } + +} diff --git a/target/classes/org/gcube/portal/databook/shared/PostType.class b/target/classes/org/gcube/portal/databook/shared/PostType.class new file mode 100644 index 0000000000000000000000000000000000000000..fd2180f2972d114c084069e00cc1fb3c8d2528c5 GIT binary patch literal 1358 zcmb7@T~iWa6vzLMyzGLj5}77yS(@=;l9iT$FNj-`2u=$$J9V?*h8VKWvN+?n=%W-~ z=+xwN(N!O+={%2=+%ywjaQ1gR&)NSu&wqdZ`f>r_2{t73F+?o88n0GbWix(c*^W_< z?-`C!wyY2F=DuN@d+}YX=@d?mObKp=!2{#ih}VrqHLf;VhYapl`Am)>mi_NO2?me0 zm3pl*NV~<2Y)0FnOyP~H78rc#d@iS^3+g6=Kb21Bi@8E3_mV;0%xI~NEYJ6=x#G@D zDU~g%8pGV%o?a~{EA?8V=BzTf!jTdUkhbExU48g2bG3q75u5lJgKU^558JzuElVl$o^_EEw^WjJ@Tk(?{ zmLx1P1iGd@X*%Yif~R;!*J9YVaZ<64PDpC^PV(ggv*IK&U2FQ2qCL?K3rYF+3~SxT zI;)KIaCLmtq=IFvFf4ZWO4p5MGtnjBZ}Y2RxL3({e$8sx74t=nuXEs!vFCXm&8XF? z4Z~^K^uLv^cKmFz2cfHp^#!^|7ky;%`WQC}K#}|*B3VO3a)pRw2ocE(B9aY&K!}@w zI=IP7LkLj6YeYYY`QOK{V0tjYr-j0zZY3kV6A@CcX`aN8?jO2A!7z_fsSvVd6u z;lO2GBp`jG?yfdQHQn7tNYg!SOlrEfjVVo++L+dKxs6#(4^S$iog(&`H1**D{f4-D z(wrjKZ1<5-_iW@qKa42N7k8Wf%e2VB}HQsXNX@l@=^h%#UZ8h{7^LaVF8ai z$Cqfm{P;*4F@4(=z0i|f{Eln<9FONdi5GHNm)+>Y5E+oTWjycnh>{@wE`N|k&yn~J Q_V06jSQQ=Cur6ZiHwcs@<^TWy literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/PostType.java b/target/classes/org/gcube/portal/databook/shared/PostType.java new file mode 100644 index 0000000..b86c0c7 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/PostType.java @@ -0,0 +1,18 @@ +package org.gcube.portal.databook.shared; + +/** + * @author Massimiliano Assante ISTI-CNR + * + */ +public enum PostType { + JOIN, SHARE, PUBLISH, TWEET, CONNECTED, + /** + * Special case used when accounting + */ + ACCOUNTING, + /** + * Special case used when a Feed is removed + */ + DISABLED; +} + diff --git a/target/classes/org/gcube/portal/databook/shared/PrivacyLevel.class b/target/classes/org/gcube/portal/databook/shared/PrivacyLevel.class new file mode 100644 index 0000000000000000000000000000000000000000..41d497472fe002499e4b5b1e8070d7057a81fd53 GIT binary patch literal 1320 zcmb7@T~E_c7{~vIjdd#(#?UD*iXzB1UJ3~KvPqcBG>c^;bS!DSFx{x5ST@piOBO$j zUqQzOL?iLq4`qDLaY}EzSTFjV-|2Z?`#(Q_eZ2y(i5&?;3@c5yuGVYqs->PaUC(sX zBhxdh&E^NSb!@uUk-G2N9kbTetd8YK2r`VGm>pAf%tl?!H`=ER(*8lAk}c;MRBfPe zX$Co0Di-s(a-mdY2v!dAI_>F&;%hDcj))<&UpgpfHNH4}sTFbzBl+Ut-h3si9rD9# zZwJm9&eR;cVS76afkd)Gd2`JpD~w?o3=;}&;ufXL^pC_7+I7Ra=h}^Wx{$0y=db%v;~$!^QDP8B@H zCPTz@U9($jo^=^g{!x^wCsxf%7ktzCyG7$6Rfw`m?-_D_xBdi^1O7GM@>2y{c*d~h zkC$`IRx9l*;$MR6hPX_**7RoEty!;ZKGt!+u2=b4>Q%Sv4byA8^gZhf$^A0}7QB<* zU8nyVpt~mRPI8?9WJw~zk~)MXVF*i_5SHWsM5nkI$TLVP8pRmJi4uJx=Fi7(U`A{_ zaDmu4;sWjj1xyN<9u_bo;9f|;tbhlSfH?v4VF3%#(07U#=pn8f!5$`cW4MPI-3awC zs~b`ebGi}kVL?B~;ulIkge1LXvY_&c)KW_9@-K9C`o*qO>!SJ8(#!>xt{p>kfMz0` zl>T~|cTJaM1*?7cZJHQ&kN2=>ya}YPj0~@GFED)xb@{VM$jkT>jif1dc#JJ<_hY1} aAf8K(vD77=`~dsE-w>XQ2x(-5eeoMkDJJCr literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/PrivacyLevel.java b/target/classes/org/gcube/portal/databook/shared/PrivacyLevel.java new file mode 100644 index 0000000..9f21298 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/PrivacyLevel.java @@ -0,0 +1,9 @@ +package org.gcube.portal.databook.shared; +/** + * @author Massimiliano Assante ISTI-CNR + * + * @version 1.0 July 6th 2012 + */ +public enum PrivacyLevel { + PRIVATE, CONNECTION, VRES, SINGLE_VRE, PORTAL, PUBLIC; +} diff --git a/target/classes/org/gcube/portal/databook/shared/RangeFeeds.class b/target/classes/org/gcube/portal/databook/shared/RangeFeeds.class new file mode 100644 index 0000000000000000000000000000000000000000..e9fa775fea533f7840b23c71f4fa825b633e3f15 GIT binary patch literal 1413 zcma)5T~8B16g|^VsMP{OTd6`((6*@ipl>COs3B?6D4~S+X?H9OOSjo>jrf~<&_rV5 zgFnC@Wjr%mX~5Mso1Kq)@0@$iy)!?5eg6UAIcjOd1hzfDXZ5kUEi1IEoT_i1?JmMuP+Hf zyhc>aPHU!#ENTor*rr5dSK;6=1&cBRZiM&mriN@N<%W;fC` zdmfFEX?r8TtM(jyopY0JKGm0%?$>JItF8=`jSUt(&OeD5KX!r7ET(%v+YPhMBE>Z? z8pj+h&o~Rt$=Ww8d@&(Q95XxyEFys=+~z7924NX1+-ZP3BSOf60XpSAPG3#~)k+sA z)*fGARYS%J0{#h(D;)D=R3L+*fi8!~#?S;XyfvqsVIIR>u0sOal4T-3Ypik93M|f{ zg0Cokq9JC|X_-JNlKnc$0i$ x=WB#EA_;9`>k{Ol0omt1B({B}ieY0mNo?yM#KLY*YL+rJ6GVGtxKvQ(jNf~QC$s feeds; + + public RangeFeeds() { + super(); + } + + public RangeFeeds(int lastReturnedFeedTimelineIndex, ArrayList feeds) { + super(); + this.lastReturnedFeedTimelineIndex = lastReturnedFeedTimelineIndex; + this.feeds = feeds; + } + + public int getLastReturnedFeedTimelineIndex() { + return lastReturnedFeedTimelineIndex; + } + public void setLastReturnedFeedTimelineIndex(int lastReturnedFeedTimelineIndex) { + this.lastReturnedFeedTimelineIndex = lastReturnedFeedTimelineIndex; + } + public ArrayList getFeeds() { + return feeds; + } + public void setFeeds(ArrayList feeds) { + this.feeds = feeds; + } + + +} diff --git a/target/classes/org/gcube/portal/databook/shared/RangePosts.class b/target/classes/org/gcube/portal/databook/shared/RangePosts.class new file mode 100644 index 0000000000000000000000000000000000000000..8873579fc908c8fd2f4a5a14f35f19c642b32abc GIT binary patch literal 1402 zcma)5U2hUW6g>kJ3Zk@FJ}kDSwN;?%KImH;Vl^=#A=vO?GEv8~4wdgn*Lg2Ht`b;r zXzpfkNA0i~`5C_IzJnw4GtFBal9HdVNU< z;x(gkcH2`m=+Zk)f+csIz7sSB;a18 z(mj@xMM>jeA~B{E(X8ERC_9D|G!Uki=CvJ&Pi9xlI%G7iQ?5mp z(QNi2k7lo`aHcY}23fyUcA~QnBk^ws7KF+h825M9;QEoiE z#IlBr69oJc919$aWK<%9vVpFK*T&EUFuXOV9PSz-D_n;JbR^3{0;^c#s1;b8Lj|8v z{=h)Yl+!YSN+kQLF-l)U!{?220^Q3))mR*n54i4?(r;iV)HLT%O82| ucS7rtgtl=13gm$S+2=kawtdaTurZq?w)GEUVYerqCF! posts; + + public RangePosts() { + super(); + } + + public RangePosts(int lastReturnedPostTimelineIndex, ArrayList feeds) { + super(); + this.lastReturnedPostTimelineIndex = lastReturnedPostTimelineIndex; + this.posts = feeds; + } + + public int getLastReturnedPostTimelineIndex() { + return lastReturnedPostTimelineIndex; + } + public void setLastReturnedPostTimelineIndex(int lastReturnedPostTimelineIndex) { + this.lastReturnedPostTimelineIndex = lastReturnedPostTimelineIndex; + } + public ArrayList getPosts() { + return posts; + } + public void setPosts(ArrayList posts) { + this.posts = posts; + } + + +} diff --git a/target/classes/org/gcube/portal/databook/shared/RunningJob.class b/target/classes/org/gcube/portal/databook/shared/RunningJob.class new file mode 100644 index 0000000000000000000000000000000000000000..568cebcd759c9e91556dcef0d0b0fab2a73840b8 GIT binary patch literal 2554 zcmbtUX>S`<6g|)JGI5;+H*I4RT&Ek3lhjEQ3T>8_raMm3)*%QXgvR#ZPU3hhFO>kP zzkXJ)2sR!W)e{GL^4 zgb-Aia8GR~le22JS+>77^JPmRu;=6-6cwV`?yX#-M!FS+5P#e<4+sm^8)ly0)sy(v{R-1FxuGo!rg`w2Uu7ZEVDOzC+AsWFb#uUb~ zcE#Fi9^|dsjusouIt8=5Ycc_fZy)*_Pi+dDf48u%PgM0oYA|DulVfJkurZj(cAukBWre(is)X-UFlI=&B9j zio%(G&u=yDa?z?8SXPL1%OLqx7>l?n^>)#~CoJ}i;VBj`=XBcsM&A?suN8RlfH|l+f`k*hE?&6ifC+`OP zjHK;0Bk3ly>}fTgY%8d*6-M|Dh5b#l>h?|uPu}`kXa`wFIj31GSa)stK#Xd%Od4PU zew^Y6Hh>G_?lgBoaE7B0{77Vwb5aP>vn@=f=URxT=UbRc$NViM(y>4b$u4(-LWw8$ zG^L&+*Lj@81;lU>XK~4mx2`$c@dPc&iH4+`o~TPogED2!IAtDO&>CAS#<=m6eJlY zKdA4mfhp4t4A1;1rr)kzVlcb}&&aE9=X__+o;})k@BeuN;5upwMi_1eVasUQorYr^ z1YyiQqse352!h8(w9iAQX_))Lvz^EZ&6vk-6ub6{9lL?AAjvTHh(G0q$NiR3@jGn> z{XyN_Huq{P_bPjLt-T$y@{r+n^|*_ah_Sk{S^1Q4dbM7wRkns!n&^S=*SC*WpZb9P zXnK;%ZLD|N++Pb_$8UOvVzr|knQ`d)Es`)=+1jaH*j=gaR7{4_Z(p+=wQPH?@5W0E ziF{#~A-Nhf9Th1RQw$SU&^DFI|!mU%7S4=!zp~jkS_N-^Z8+!8^cqD-3)cl zX-FZhLQ(N8!^sDNHFp?va-RFxX$r)58We$0Rh(m(JVMw(yG=@Zs0$iYfy$`(kx*6Y zj&gAzsKTCB!Bx%xv3WXtDV=EhqlyuzN9Pn93K1ts}Fa zaVv^CttDno{cAwRT(1Bzd9a7*>ZBgc+Qg9rQn z)P_ioA{EwuXV@BS>&Lcm{FDll?`yb+b%q;*)TRIsR+gue`Wacy%QBbJ&&u+= zEWc0dKgcpK%c7!Rl;wi@nz#~O%$ioRi+R&Zb#dOb(p}_DOX*_4d=BF;T66?g>3>ej z%#x^4%#+jw5?UsynB6u!6U8@HS$I%OoPLF+OP{i_58KL6BrAQ6B8e0NvN|ii!rEJ~FZYdLgODTml}r+2 F^*;<&t@{7~ literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ShowUserStatisticAction.java b/target/classes/org/gcube/portal/databook/shared/ShowUserStatisticAction.java new file mode 100644 index 0000000..25278f6 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ShowUserStatisticAction.java @@ -0,0 +1,25 @@ +package org.gcube.portal.databook.shared; + +/** + * Enum class that specify the possible actions to take when the GCubeSocialNetworking.SHOW_STATISTICS_ACTION_OID parameter + * is found in the page url + * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + */ +public enum ShowUserStatisticAction { + + POSTS_MADE_BY_USER("Your recent posts"), + LIKES_MADE_BY_USER("Posts you liked"), + COMMENTS_MADE_BY_USER("Posts you commented"), + LIKES_GOT_BY_USER("Likes to your posts"), + COMMENTS_GOT_BY_USER("Replies to your posts"); + + private final String actionHumanFriendly; + + private ShowUserStatisticAction(String s) { + actionHumanFriendly = s; + } + + public String getHumanFriendlyAction() { + return this.actionHumanFriendly; + } +} diff --git a/target/classes/org/gcube/portal/databook/shared/UserInfo.class b/target/classes/org/gcube/portal/databook/shared/UserInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..85b6f4c31c9bee9ed91295772cd8563c12595d7f GIT binary patch literal 3448 zcmchY+j84f6o!8#j_ssMQ`{zPXn{1OsiQb?8`?t20n(DtKn`tA(Da02D~?)Q3bI@V zo&=tN8!lj`PG?|-2jDSy5Qcwk*-k9Wom?Zf$LAOe#T{QD~&nlNS^q9GvTXFoY z^<@pQk}1Kp9SvP(zGOQZ67F}-_WA->o(%{pzFo}TGt2uc<^d79H|&CA`W27g-ELhm z(~8|XGe-h4C&xWzRbSu+;HM6r5cxsYOcKGA}9Q1@IF}B?e4e#qXg``+lbm)O~ zRYz}Njp;ZYSmQeS0&7CY8N4N5WObwh>$;A!IHzHt`J}!-sGnAE!Sd&i<=?sVSgY<# z^K$dD{s`$r(o=LNB^RXsDSmbAiSHI0^&sz#JqbpmK;+%gQyQ*CbTaB!2HL|YN$f{N&Ynp!gl|8@;=V9Xl?}MEAfTPB-%Xp2qe^W~?@h;(j_YlJn z-l3%ji|{VzK>IxBJ8CX3D@T9xSx~3MkuhGyu#u@^#F(gJ)EJCakv0aqsxXZHcoi9= zKT*Y`F_^64nndk{L^T)}xWcHT^mUa@D^1)n`ZpMNoNqF`PvANx71iS)VvUNil|-_g zDQSXg4^z?v>0jnVsF<=usxD=TSaD^ETnS}~U`ej8?|X_A1Dw$)*A3o9xGcv&xK}WK z4iM#CUWksveCAfsWB z6@sj`0g*ftkl9F(bQt78B*&^RfuG z*9L4!b;P3rk7J1iE~sBbYBm|x%#K9-GFr3Aux2HqIc?CS3keAS6}-#g{j7coK<#slLOh7Ylk`ieK&BVs=c>`}2F1$J8OCxLB<{VcFEhcHw5z@8L)FR-s2Vn6kQ j_903~XEH!oz+-nS6UoN|RABS@=(kX6{1#l5S_l6EFIaj( literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/UserInfo.java b/target/classes/org/gcube/portal/databook/shared/UserInfo.java new file mode 100644 index 0000000..74f9c2a --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/UserInfo.java @@ -0,0 +1,121 @@ +package org.gcube.portal.databook.shared; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * @author Massimiliano Assante ISTI-CNR + */ +@SuppressWarnings("serial") +public class UserInfo implements Serializable { + + public transient final static String USER_INFO_ATTR = "USER_INFO_ATTR"; + + private String username; + + private String fullName; + + private String avatarId; + + private String emailaddress; + + private String accountURL; + + private boolean male; + + private boolean admin; + + private HashMap ownVREs; + + public UserInfo() { + super(); + } + + public UserInfo(String username, String fullName, String avatarId, + String emailaddress, String accountURL, boolean male, + boolean admin, HashMap ownVREs) { + super(); + this.username = username; + this.fullName = fullName; + this.avatarId = avatarId; + this.emailaddress = emailaddress; + this.accountURL = accountURL; + this.male = male; + this.admin = admin; + this.ownVREs = ownVREs; + } + + public String getAccountURL() { + return accountURL; + } + + public void setAccountURL(String accountURL) { + this.accountURL = accountURL; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getAvatarId() { + return avatarId; + } + + public void setAvatarId(String avatarId) { + this.avatarId = avatarId; + } + + public String getEmailaddress() { + return emailaddress; + } + + public void setEmailaddress(String emailaddress) { + this.emailaddress = emailaddress; + } + + public boolean isMale() { + return male; + } + + public void setMale(boolean male) { + this.male = male; + } + + public HashMap getOwnVREs() { + return ownVREs; + } + + public void setOwnVREs(HashMap vreMap) { + this.ownVREs = vreMap; + } + + public boolean isAdmin() { + return admin; + } + + public void setAdmin(boolean admin) { + this.admin = admin; + } + + @Override + public String toString() { + return "UserInfo [username=" + username + ", fullName=" + fullName + + ", avatarId=" + avatarId + ", emailaddress=" + emailaddress + + ", accountURL=" + accountURL + ", male=" + male + ", admin=" + + admin + ", ownVREs=" + ownVREs + "]"; + } + + +} diff --git a/target/classes/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.class b/target/classes/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.class new file mode 100644 index 0000000000000000000000000000000000000000..3feceab8029363757902eca40b8ec3d1d558b1f6 GIT binary patch literal 445 zcmbu5zfQw25XL`;(m*H_ieQF~KN4Qpii%K0r>IL&_e)}>hQzKMr|N4lAu;d(JQU(m zDj1Mh@JT2C&fnSJ`TgVd4Zt;eAp(J0>vEZ=b)w|lI!}en$WvnNldNXsR3_C@4sB7F zW=y3TTR*b3$?lh_ntN?ch?cn0Tj6-anrTw1zfQ z5jL>h!6w=Q-B=qnuFFKZ2TBSh(2H$K#gv?GcwKDynXUxx;(vPY3xuVrD#}+c{qiUf zO>FH_HPVfjlRv)Us%ge41W(f}!NDVO4w(iBIDq!W<{9 literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java b/target/classes/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java new file mode 100644 index 0000000..536e6a6 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class ColumnNameNotFoundException extends Exception { + public ColumnNameNotFoundException(String message) { + super(message); + } +} diff --git a/target/classes/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.class b/target/classes/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.class new file mode 100644 index 0000000000000000000000000000000000000000..659e71a24cf90749dc657362ad9ba718e3cc021f GIT binary patch literal 442 zcmbu5&q@O^5XQe*YggB5wW3$?<{vN@Z22k@c9 z*;@1*vY1Mz8(tM#ex@tJb^Jf;eL`5Os*?HgpO0sJV$Y*K;LloK9#JTsohH)H?&_3a0Mmv|hYA&^*?#o4$TQCwK(RUW6xtC6+G zaXC?r(wNTTK2f^&Vc+_`txWpyY)pmM)&yt@tQ@IR73a!i@t+HU)@yCFe=D%FJNWBx z;GH&EGH>Y(1)A?|N&#*PtY3|ISLr+@7vh${>fwasCtG?sQKy_u>hzV25Mr^71>6=` zyQX4qSbN-QV;LO=r;371D)9U|*Ew{T)sqmb0$r&~X{?upqmqo5+DOlcrc+ZT&9K~U zV;%PdLT_h1Gw$8qT;?Rg4J-;Q4YZ;C>SRRjP>pgD=nU*w;qLKtq61sGG4*u~XyYG$;6=>E#?7hU(lS| zH=le*__-5Zp#AI|OPv*FPkEnX?E?3|vS$Mim`8kqBOmc=J!DDFqOrl2dTlaoaqe1@ MEHzl}vev-%Z$j_C(f|Me literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java b/target/classes/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java new file mode 100644 index 0000000..52c2dce --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java @@ -0,0 +1,9 @@ +package org.gcube.portal.databook.shared.ex; + + +@SuppressWarnings("serial") +public class FeedIDNotFoundException extends Exception { + public FeedIDNotFoundException(String message, String postId) { + super("The Post having id: " + postId + " is not present in the database: " + message); + } +} \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.class b/target/classes/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.class new file mode 100644 index 0000000000000000000000000000000000000000..2ec9bdd7e03e0eeac3b7b4ab1d32d4800088a1ba GIT binary patch literal 439 zcmbu5zfQw25XL`;&_E~@ieN-ytIsj|A|Rnd1dT?^dA|8hPM2I!Q*fan1=8;fX>&_GkR})32ZZL8Hrn?H2Pg55VC0=PdG~ZoXx!RN zMOedT3+reS+OaljSWOe<9%ND|LMOJVEXLC5npee!pXics6aUM3mk>@>S;~C*&M$|A zXk;sws=ltB9R2wP7j-L+K|D#lh=a%B95VF~Z~)D-^A~J9^DaQdIr^%yGQ<}1;fh<> QW@0^d&|coP%M@Vm6Ar*}DgXcg literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java b/target/classes/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java new file mode 100644 index 0000000..a7d5cb0 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class InviteIDNotFoundException extends Exception { + public InviteIDNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.class b/target/classes/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.class new file mode 100644 index 0000000000000000000000000000000000000000..644957477ab820f024b9d0e1fa4bb219a9ba81e6 GIT binary patch literal 451 zcmbu5&q@O^5XQf(wX18jTG6|n`~&9Vtx}L;L0EcO>3w!LY@^$xWV5BO8*1AF#S)D35x6V^3bMlm0`y{I=Ih9Mbl=o(# zy-Ga!x*A(QvbD+YmYJG+ZB2-lz~Lh;NS0&@`F$YJzR^befxyvO{3A%b)28U3PXt;+ zo2v*L*zRBxZGmpAjT+apRJjLAOC`{YZARsUoNjnsZ276K1cvdy-S-8;nW`!(R&V`s zDG(*Lc9|OK#?9%UUvbs6;{<{yYL?*Ou{eiJ0|XpE`{MEiThF`;5OI#as;msL!+gBv S4tAMXk3Do(ckMF;IQRsy$9Ee5 literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java b/target/classes/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java new file mode 100644 index 0000000..5f4f9c2 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class InviteStatusNotFoundException extends Exception { + public InviteStatusNotFoundException(String message) { + super(message); + } +} diff --git a/target/classes/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.class b/target/classes/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.class new file mode 100644 index 0000000000000000000000000000000000000000..c8eb8bad14d47d6e397a6b0f500a4c3313b6d900 GIT binary patch literal 433 zcmbu4y-ve06otnKqsJoL`sc9Nlj)VGIOh^no01t(@ zDHRNe318{T-}SM5&ilvf8-PpnLU@GO*g_OplPWPc*2z-j(#h1Asi-H?s$8grNc2?Q z-wur%n5N3_7MYqmZK@DHVgFG+Nm0tG5Z?!c;7V88^$7ZCpsj?3;Eft}cm`s*qX?4r1q330-t&gKW;$O5EaSY-V?IJFY!aZc_!{Y*iv-1~hJoC;E|&vNFUL^Wlm+*k)oq NcF4&Z zU|?auC!PGe`*gm~?;o#k0It!E5C|mJ6|%_cRLO;Po=TaMr_|a9S4PL6ga%6N0KF(LVh;{S~uEg-xoMKO@0Jp@3bj; zXH$W2U~?5?1KVwEq9xEtv{9pao+>w?v{VA!#AZ}Z$?1mI#n8`mB{2F|BRzp=uBwWP z)w91A7Kq2Tc9|OLX0gk^e$Z7j2`3QjvpIr;&2o;I`Up6H*7?N?wx0PGAm$u@RaqHf WhxvHTZR|3!9((AlX6-WtIQRshw}dGG literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java b/target/classes/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java new file mode 100644 index 0000000..e70f779 --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class NotificationChannelTypeNotFoundException extends Exception { + public NotificationChannelTypeNotFoundException(String message) { + super(message); + } +} diff --git a/target/classes/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.class b/target/classes/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.class new file mode 100644 index 0000000000000000000000000000000000000000..817792393cd9297a54a1dba9c673f5674f3cda72 GIT binary patch literal 457 zcmb`DzfQw25XQd?A%RdR6v2+fz#j=OY(-s4Dy1UI_Wu17dJi+>DbXLXr(&nE=G zZ!#5O1KTZZA|SM5U8+$%OO(BrNudax*rc+UNUIxOi@uxciZF=(Vg4>5oT;jk`RcV_ za}uJlscou;x|!$nkMFo@8sG%PTQ!F`cs0%;Qx6^o5L{foVC$JH4-x0+OJ!$>9p>XT Sx3J5^e(a&W>b1}0;ouX;NO+_G literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java b/target/classes/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java new file mode 100644 index 0000000..13c0ebb --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class NotificationIDNotFoundException extends Exception { + public NotificationIDNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.class b/target/classes/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.class new file mode 100644 index 0000000000000000000000000000000000000000..7f36a1097a6cea2092a9cb75008dbde31473ee35 GIT binary patch literal 463 zcmb`DzfQw25XQd?p@C2+6v57d_#@$kt*8rXS)wkjx;u$U4QU)XPE{U@35kIR;Gqzg zQo+E$f=@c#@BHa}pWi=T-vC^r8^9wBjLk%r)Ugt!u}2txAPjiji^p zUMJFNQ%s&p#XK~1kq(xLDw}2ipK$mf7gFT1$i(*rp>?AR?fQhHv*<@Kc2*Zz?|e$| zZ%wK~Y+$>MO|%G|NEd2U&tqjLGR_sD8<|ArQ)zX>>!$B!x+2^~|KgxW28%h{qsw%nh`hwv9sn72ixNuF!kYa0IiG57i>LqIEU99WGh>~~WvZNtjd_;kL|IBDE##xs zbCoP3no~Yn&S+p<-&94~TO>4d+7tnNf#WANS29;cCciHP8h5(Tt}AeI5&Z~;&gvrT zT#g0&dy`U#E$lY2jfOxg(gh8wX-syc;+zE9kx5iOR#w-%Y5H!WOM!>zUmSD}y z%GU4w+EgGMn#v~B*Y!r{e}2hLJpyMC?5sY5gY9t+n7Z&dfX3DJ3wBmqc?da&UtLxP X*keB3a1;AXtj7Ub>sg0P9*#Z%S7Up& literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java b/target/classes/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java new file mode 100644 index 0000000..10fc82b --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class PrivacyLevelTypeNotFoundException extends Exception { + public PrivacyLevelTypeNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/target/classes/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.class b/target/classes/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.class new file mode 100644 index 0000000000000000000000000000000000000000..cb8455168a8c64fa7de13af094c7eb788e275b0c GIT binary patch literal 457 zcmb`DzfQw25XL`;kU%IDieN`#;E#kCwxTXknF0f?x;u%L8dAHm9aJ8R35kIR;Gqzg zQo+E$f=@c#@BHcWo!>uR-vC^q7b9Rujjec9G`Zw+W4)+(DZI#ydEjm;tSq@)@UbyB zLOqCWZn!Aq+$*DFgbe%l;!*Hg=!$<|Fho~MD?ea3ILUqlBX7y4e>!0Z zQ&Y+WYuM~y9T7t}Q(E3Ovs~J-$ZN^a%S<8aiLk2WRWtNcrM0)I?yY$*63b6MH!uxr+ literal 0 HcmV?d00001 diff --git a/target/classes/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java b/target/classes/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java new file mode 100644 index 0000000..7afbe1d --- /dev/null +++ b/target/classes/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java @@ -0,0 +1,8 @@ +package org.gcube.portal.databook.shared.ex; + +@SuppressWarnings("serial") +public class TooManyRunningClustersException extends Exception { + public TooManyRunningClustersException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..fa3e28b --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,3 @@ +version=1.18.0-SNAPSHOT +groupId=org.gcube.portal +artifactId=social-networking-library diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..e69de29 diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..37d42e0 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,47 @@ +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/UserInfo.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/JobStatusType.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/FeedIDNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/Post.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/CommentIDNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/NotificationChannelTypeNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/InviteOperationResult.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/server/DBCassandraAstyanaxImpl.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/server/DatabookStore.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/FeedTypeNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ClientPost.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/RangePosts.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/ColumnNameNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/client/util/Encoder.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/Like.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/NotificationChannelType.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/Notification.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ClientAttachment.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/InviteStatusNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/server/DatabookCassandraTest.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/server/RunningCluster.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/NotificationIDNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/Comment.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/FeedType.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/TooManyRunningClustersException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/PrivacyLevel.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/EnhancedFeed.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/PrivacyLevelTypeNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ImageType.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ApplicationProfile.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/InviteIDNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ClientFeed.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/NotificationTypeNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/NotificationType.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/Feed.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/InviteStatus.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/RunningJob.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/JSON.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ShowUserStatisticAction.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/RangeFeeds.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/server/Schema.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/PostType.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/client/GCubeSocialNetworking.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/ex/LikeIDNotFoundException.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/Attachment.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/server/Tester.java +/Users/massi/workspace/social-networking-library/src/main/java/org/gcube/portal/databook/shared/Invite.java diff --git a/target/social-networking-library-1.18.0-SNAPSHOT-tests.jar b/target/social-networking-library-1.18.0-SNAPSHOT-tests.jar new file mode 100644 index 0000000000000000000000000000000000000000..63129b8815e629bf6e76554095cecb542908cdfc GIT binary patch literal 2727 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 literal 0 HcmV?d00001