Browse code

FEATBL-828 Feat: store attachments

Thomas Fricker authored on 24/07/2019 09:41:55
Showing 25 changed files
... ...
@@ -50,6 +50,8 @@
50 50
       <plugin id="jul.to.slf4j"/>
51 51
       <plugin id="net.bluemind.addressbook.adapter"/>
52 52
       <plugin id="net.bluemind.addressbook.api"/>
53
+      <plugin id="net.bluemind.attachment.api"/>
54
+      <plugin id="net.bluemind.attachment.api.gwt"/>
53 55
       <plugin id="net.bluemind.authentication.api"/>
54 56
       <plugin id="net.bluemind.calendar.api"/>
55 57
       <plugin id="net.bluemind.calendar.helper"/>
... ...
@@ -43,6 +43,7 @@ import org.junit.Test;
43 43
 import org.slf4j.Logger;
44 44
 import org.slf4j.LoggerFactory;
45 45
 
46
+import net.bluemind.attachment.api.AttachedFile;
46 47
 import net.bluemind.calendar.api.VEvent;
47 48
 import net.bluemind.calendar.api.VEventOccurrence;
48 49
 import net.bluemind.calendar.api.VEventSeries;
... ...
@@ -123,6 +124,20 @@ public class VEventSeriesStoreTests {
123 124
 		assertNull(evt.main.alarm);
124 125
 		assertNull(evt.main.rrule);
125 126
 		assertEquals(2, evt.main.attendees.size());
127
+		assertEquals(2, evt.main.attachments.size());
128
+
129
+		List<AttachedFile> attachments = evt.main.attachments;
130
+		int checked = 0;
131
+		for (AttachedFile attachedFile : attachments) {
132
+			if (attachedFile.name.equals("test.gif")) {
133
+				assertEquals("http://somewhere/1", attachedFile.publicUrl);
134
+				checked++;
135
+			} else if (attachedFile.name.equals("test.png")) {
136
+				assertEquals("http://somewhere/2", attachedFile.publicUrl);
137
+				checked++;
138
+			}
139
+		}
140
+		assertEquals(2, checked);
126 141
 
127 142
 		evt.main.summary = "updated summary";
128 143
 		evt.main.location = "updated location";
... ...
@@ -894,6 +909,16 @@ public class VEventSeriesStoreTests {
894 909
 		event.status = VEvent.Status.Confirmed;
895 910
 		event.priority = 42;
896 911
 
912
+		event.attachments = new ArrayList<>();
913
+		AttachedFile attachment1 = new AttachedFile();
914
+		attachment1.publicUrl = "http://somewhere/1";
915
+		attachment1.name = "test.gif";
916
+		event.attachments.add(attachment1);
917
+		AttachedFile attachment2 = new AttachedFile();
918
+		attachment2.publicUrl = "http://somewhere/2";
919
+		attachment2.name = "test.png";
920
+		event.attachments.add(attachment2);
921
+
897 922
 		event.organizer = new VEvent.Organizer();
898 923
 		event.organizer.uri = UUID.randomUUID().toString();
899 924
 		event.organizer.dir = "bm://users/org";
... ...
@@ -14,5 +14,6 @@ Require-Bundle: net.bluemind.core.jdbc;bundle-version="1.0.0",
14 14
  net.bluemind.core.commons;bundle-version="1.0.0",
15 15
  net.bluemind.lib.jackson;bundle-version="1.0.0",
16 16
  net.bluemind.calendar.sqlschema;bundle-version="1.0.0";visibility:=reexport,
17
- net.bluemind.icalendar.persistence;bundle-version="1.0.0"
17
+ net.bluemind.icalendar.persistence;bundle-version="1.0.0",
18
+ net.bluemind.attachment.api
18 19
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
... ...
@@ -49,7 +49,8 @@ Require-Bundle: net.bluemind.calendar.api;bundle-version="1.0.0",
49 49
  net.bluemind.config,
50 50
  net.bluemind.server.api,
51 51
  net.bluemind.resource.api,
52
- net.bluemind.resource.helper
52
+ net.bluemind.resource.helper,
53
+ net.bluemind.attachment.api
53 54
 Export-Package: net.bluemind.calendar.service,
54 55
  net.bluemind.calendar.service.internal
55 56
 Bundle-Activator: net.bluemind.calendar.service.CalendarActivator
... ...
@@ -24,6 +24,7 @@ import java.util.stream.Collectors;
24 24
 
25 25
 import org.apache.commons.lang.StringUtils;
26 26
 
27
+import net.bluemind.attachment.api.AttachedFile;
27 28
 import net.bluemind.calendar.api.VEvent;
28 29
 import net.bluemind.calendar.api.VEventSeries;
29 30
 import net.bluemind.core.api.date.BmDateTime;
... ...
@@ -142,6 +143,18 @@ public class VEventValidator implements IValidator<VEventSeries> {
142 143
 			throw new ServerFault("Event title is empty", ErrorCode.EMPTY_EVENT_TITLE);
143 144
 		}
144 145
 
146
+		validateAttachments(vevent.attachments);
147
+	}
148
+
149
+	private void validateAttachments(List<AttachedFile> attachments) {
150
+		if (attachments != null && !attachments.isEmpty()) {
151
+			for (AttachedFile attachment : attachments) {
152
+				if (StringUtils.isEmpty(attachment.name) || StringUtils.isEmpty(attachment.publicUrl)) {
153
+					throw new ServerFault("Event attachment value is empty", ErrorCode.EMPTY_EVENT_ATTACHMENT_VALUE);
154
+				}
155
+			}
156
+		}
157
+
145 158
 	}
146 159
 
147 160
 	private void checkIntegerList(List<Integer> intList, int min, int max) throws ServerFault {
... ...
@@ -121,6 +121,12 @@ create table t_calendar_vevent (
121 121
   valarm_duration int[],
122 122
   valarm_repeat int[],
123 123
   valarm_summary text[],
124
+  
125
+   /*
126
+    * 3.8.1.1.  Attachment
127
+    */
128
+   attach_uri text[],
129
+   attach_name text[],
124 130
 
125 131
   item_id int4 references t_container_item(id)
126 132
 );
... ...
@@ -373,6 +373,6 @@ public enum ErrorCode {
373 373
 	/**
374 374
 	 * 
375 375
 	 */
376
-	INVALID_GROUP_MEMBER;
376
+	INVALID_GROUP_MEMBER, EMPTY_EVENT_ATTACHMENT_VALUE;
377 377
 
378 378
 }
... ...
@@ -12,4 +12,5 @@ Require-Bundle: net.bluemind.core.commons,
12 12
  net.bluemind.lib.ical4j,
13 13
  net.bluemind.neko.common,
14 14
  com.fasterxml.jackson.core.jackson-core;bundle-version="2.4.1";visibility:=reexport,
15
- com.fasterxml.jackson.core.jackson-annotations;bundle-version="2.4.1"
15
+ com.fasterxml.jackson.core.jackson-annotations;bundle-version="2.4.1",
16
+ net.bluemind.attachment.api
... ...
@@ -22,7 +22,7 @@ import java.util.ArrayList;
22 22
 import java.util.Collections;
23 23
 import java.util.List;
24 24
 import java.util.Set;
25
-
25
+import net.bluemind.attachment.api.AttachedFile;
26 26
 import net.bluemind.core.api.BMApi;
27 27
 import net.bluemind.core.api.date.BmDateTime;
28 28
 import net.bluemind.tag.api.TagRef;
... ...
@@ -50,6 +50,7 @@ public class ICalendarElement {
50 50
 	public Set<BmDateTime> rdate;
51 51
 	public RRule rrule;
52 52
 	public String url;
53
+	public List<AttachedFile> attachments = Collections.emptyList();
53 54
 
54 55
 	@BMApi(version = "3")
55 56
 	public static class VAlarm {
... ...
@@ -143,8 +144,8 @@ public class ICalendarElement {
143 144
 		 **/
144 145
 		public String member;
145 146
 		/**
146
-		 * "ROLE", for the intended role that the attendee will have in the
147
-		 * calendar component;
147
+		 * "ROLE", for the intended role that the attendee will have in the calendar
148
+		 * component;
148 149
 		 */
149 150
 		public Role role;
150 151
 		/**
... ...
@@ -156,8 +157,8 @@ public class ICalendarElement {
156 157
 		 */
157 158
 		public Boolean rsvp;
158 159
 		/**
159
-		 * "DELEGATED-TO", to indicate the calendar users that the original
160
-		 * request was delegated to;
160
+		 * "DELEGATED-TO", to indicate the calendar users that the original request was
161
+		 * delegated to;
161 162
 		 */
162 163
 		public String delTo;
163 164
 
... ...
@@ -7,5 +7,6 @@ Bundle-Vendor: www.blue-mind.net
7 7
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
8 8
 Require-Bundle: net.bluemind.core.jdbc;bundle-version="1.0.0",
9 9
  net.bluemind.icalendar.api,
10
- net.bluemind.core.commons
10
+ net.bluemind.core.commons,
11
+ net.bluemind.attachment.api
11 12
 Export-Package: net.bluemind.icalendar.persistence
... ...
@@ -18,12 +18,16 @@
18 18
   */
19 19
 package net.bluemind.icalendar.persistence;
20 20
 
21
+import java.sql.Array;
21 22
 import java.sql.Connection;
22 23
 import java.sql.PreparedStatement;
23 24
 import java.sql.ResultSet;
24 25
 import java.sql.SQLException;
25 26
 import java.sql.Types;
27
+import java.util.ArrayList;
28
+import java.util.List;
26 29
 
30
+import net.bluemind.attachment.api.AttachedFile;
27 31
 import net.bluemind.core.jdbc.Columns;
28 32
 import net.bluemind.core.jdbc.JdbcAbstractStore.EntityPopulator;
29 33
 import net.bluemind.core.jdbc.JdbcAbstractStore.StatementValues;
... ...
@@ -52,7 +56,9 @@ public class ICalendarElementColumns {
52 56
 			.col("exdate_precision", "e_datetime_precision") //
53 57
 			.col("rdate_timestamp") //
54 58
 			.col("rdate_timezone") //
55
-			.col("rdate_precision", "e_datetime_precision");
59
+			.col("rdate_precision", "e_datetime_precision") //
60
+			.col("attach_uri") //
61
+			.col("attach_name");
56 62
 
57 63
 	public static StatementValues<ICalendarElement> values() {
58 64
 		return new StatementValues<ICalendarElement>() {
... ...
@@ -104,6 +110,17 @@ public class ICalendarElementColumns {
104 110
 				DateTimeType.setDateTimeArray(conn, statement, index, value.rdate);
105 111
 				index += DateTimeType.LENGTH;
106 112
 
113
+				String[] attachmentUrls = new String[value.attachments.size()];
114
+				String[] attachmentNames = new String[value.attachments.size()];
115
+
116
+				for (int i = 0; i < value.attachments.size(); i++) {
117
+					attachmentUrls[i] = value.attachments.get(i).publicUrl;
118
+					attachmentNames[i] = value.attachments.get(i).name;
119
+				}
120
+
121
+				statement.setArray(index++, conn.createArrayOf("text", attachmentUrls));
122
+				statement.setArray(index++, conn.createArrayOf("text", attachmentNames));
123
+
107 124
 				return index;
108 125
 
109 126
 			}
... ...
@@ -157,10 +174,34 @@ public class ICalendarElementColumns {
157 174
 				value.rdate = DateTimeType.getDateTimes(rs, index);
158 175
 				index += DateTimeType.LENGTH;
159 176
 
177
+				String[] attachmentUrls = arrayOfString(rs.getArray(index++));
178
+				String[] attachmentNames = arrayOfString(rs.getArray(index++));
179
+
180
+				List<AttachedFile> attachments = new ArrayList<>(attachmentUrls.length);
181
+				for (int i = 0; i < attachmentUrls.length; i++) {
182
+					AttachedFile file = new AttachedFile();
183
+					file.publicUrl = attachmentUrls[i];
184
+					file.name = attachmentNames[i];
185
+					file.expirationDate = 0l;
186
+					attachments.add(file);
187
+				}
188
+
189
+				value.attachments = attachments;
190
+
160 191
 				return index;
161 192
 			}
162 193
 
163 194
 		};
164 195
 
165 196
 	}
197
+
198
+	protected static String[] arrayOfString(Array array) throws SQLException {
199
+		String[] ret = null;
200
+		if (array != null) {
201
+			ret = (String[]) array.getArray();
202
+		} else {
203
+			ret = new String[0];
204
+		}
205
+		return ret;
206
+	}
166 207
 }
... ...
@@ -14,5 +14,6 @@ Require-Bundle: net.bluemind.todolist.api;bundle-version="1.0.0",
14 14
  net.bluemind.core.commons;bundle-version="1.0.0",
15 15
  net.bluemind.todolist.sqlschema;bundle-version="1.0.0";visibility:=reexport,
16 16
  net.bluemind.icalendar.persistence;bundle-version="1.0.0",
17
- net.bluemind.tag.persistance
17
+ net.bluemind.tag.persistance,
18
+ net.bluemind.attachment.api
18 19
 Export-Package: net.bluemind.todolist.persistance
... ...
@@ -30,6 +30,7 @@ Require-Bundle: org.eclipse.core.runtime,
30 30
  net.bluemind.directory.api,
31 31
  net.bluemind.core.container.hierarchy.hook,
32 32
  net.bluemind.user.persistance,
33
- net.bluemind.core.container.sharding
33
+ net.bluemind.core.container.sharding,
34
+ net.bluemind.attachment.api
34 35
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
35 36
 Export-Package: net.bluemind.todolist.service
... ...
@@ -18,6 +18,11 @@
18 18
  */
19 19
 package net.bluemind.todolist.service.internal;
20 20
 
21
+import java.util.List;
22
+
23
+import org.apache.commons.lang.StringUtils;
24
+
25
+import net.bluemind.attachment.api.AttachedFile;
21 26
 import net.bluemind.core.api.date.BmDateTime;
22 27
 import net.bluemind.core.api.date.BmDateTimeWrapper;
23 28
 import net.bluemind.core.api.fault.ErrorCode;
... ...
@@ -52,7 +57,20 @@ public class VTodoValidator {
52 57
 				throw new ServerFault("RRule.until is prior to event date", ErrorCode.INVALID_PARAMETER);
53 58
 			}
54 59
 		}
60
+		
61
+		validateAttachments(vtodo.attachments);
55 62
 
56 63
 	}
57 64
 
65
+	private void validateAttachments(List<AttachedFile> attachments) {
66
+		if (attachments != null && !attachments.isEmpty()) {
67
+			for (AttachedFile attachment : attachments) {
68
+				if (StringUtils.isEmpty(attachment.name) || StringUtils.isEmpty(attachment.publicUrl)) {
69
+					throw new ServerFault("Event attachment value is empty", ErrorCode.EMPTY_EVENT_ATTACHMENT_VALUE);
70
+				}
71
+			}
72
+		}
73
+
74
+	}
75
+	
58 76
 }
... ...
@@ -148,6 +148,12 @@ create table t_todolist_vtodo (
148 148
   valarm_duration int[],
149 149
   valarm_repeat int[],
150 150
   valarm_summary text[],
151
+  
152
+  /*
153
+    * 3.8.1.1.  Attachment
154
+    */
155
+   attach_uri text[],
156
+   attach_name text[],
151 157
 
152 158
   item_id int4 references t_container_item(id) primary key
153 159
 );
154 160
new file mode 100644
... ...
@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<classpath>
3
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
4
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
5
+	<classpathentry kind="src" path="src"/>
6
+	<classpathentry kind="src" path="generated/"/>
7
+	<classpathentry kind="output" path="target/classes"/>
8
+</classpath>
0 9
new file mode 100644
... ...
@@ -0,0 +1,7 @@
1
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
3
+<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
4
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="com.google.gdt.eclipse.core.webAppProjectValidator"/>
5
+<mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
6
+<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
7
+</launchConfiguration>
0 8
new file mode 100644
... ...
@@ -0,0 +1,7 @@
1
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
3
+<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
4
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="com.google.gwt.eclipse.core.gwtProjectValidator"/>
5
+<mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
6
+<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
7
+</launchConfiguration>
0 8
new file mode 100644
... ...
@@ -0,0 +1,49 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<projectDescription>
3
+	<name>net.bluemind.attachment.api.gwt</name>
4
+	<comment></comment>
5
+	<projects>
6
+	</projects>
7
+	<buildSpec>
8
+		<buildCommand>
9
+			<name>org.eclipse.jdt.core.javabuilder</name>
10
+			<arguments>
11
+			</arguments>
12
+		</buildCommand>
13
+		<buildCommand>
14
+			<name>org.eclipse.pde.ManifestBuilder</name>
15
+			<arguments>
16
+			</arguments>
17
+		</buildCommand>
18
+		<buildCommand>
19
+			<name>org.eclipse.pde.SchemaBuilder</name>
20
+			<arguments>
21
+			</arguments>
22
+		</buildCommand>
23
+		<buildCommand>
24
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
25
+			<triggers>full,incremental,</triggers>
26
+			<arguments>
27
+				<dictionary>
28
+					<key>LaunchConfigHandle</key>
29
+					<value>&lt;project&gt;/.externalToolBuilders/com.google.gdt.eclipse.core.webAppProjectValidator (40).launch</value>
30
+				</dictionary>
31
+			</arguments>
32
+		</buildCommand>
33
+		<buildCommand>
34
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
35
+			<triggers>full,incremental,</triggers>
36
+			<arguments>
37
+				<dictionary>
38
+					<key>LaunchConfigHandle</key>
39
+					<value>&lt;project&gt;/.externalToolBuilders/com.google.gwt.eclipse.core.gwtProjectValidator (40).launch</value>
40
+				</dictionary>
41
+			</arguments>
42
+		</buildCommand>
43
+	</buildSpec>
44
+	<natures>
45
+		<nature>org.eclipse.pde.PluginNature</nature>
46
+		<nature>org.eclipse.jdt.core.javanature</nature>
47
+		<nature>com.google.gwt.eclipse.core.gwtNature</nature>
48
+	</natures>
49
+</projectDescription>
0 50
new file mode 100644
... ...
@@ -0,0 +1,17 @@
1
+Manifest-Version: 1.0
2
+Bundle-ManifestVersion: 2
3
+Bundle-Name: Tests
4
+Bundle-SymbolicName: net.bluemind.attachment.api.gwt;singleton:=true
5
+Bundle-Version: 4.1.0.qualifier
6
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
7
+Require-Bundle: net.bluemind.core.commons.gwt;bundle-version="4.1.0";visibility:=reexport,
8
+ com.google.gwt.user;resolution:=optional,
9
+ net.bluemind.attachment.api;bundle-version="4.1.0";visibility:=reexport,
10
+ net.bluemind.user.api.gwt;bundle-version="4.1.0";visibility:=reexport,
11
+ net.bluemind.restbus.api.gwt;bundle-version="4.1.0";visibility:=reexport
12
+Export-Package: net.bluemind.attachment,
13
+ net.bluemind.attachment.api.gwt.endpoint,
14
+ net.bluemind.attachment.api.gwt.serder,
15
+ net.bluemind.attachment.api.gwt.js
16
+Automatic-Module-Name: net.bluemind.attachment.api.gwt
17
+
0 18
new file mode 100644
... ...
@@ -0,0 +1,8 @@
1
+source.. = src,\
2
+           generated/
3
+bin.includes = META-INF/, \
4
+	.
5
+
6
+
7
+
8
+     
0 9
\ No newline at end of file
1 10
new file mode 100644
... ...
@@ -0,0 +1,31 @@
1
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3
+	<modelVersion>4.0.0</modelVersion>
4
+	<artifactId>net.bluemind.attachment.api.gwt</artifactId>
5
+	<packaging>eclipse-plugin</packaging>
6
+
7
+	<parent>
8
+		<groupId>net.bluemind</groupId>
9
+		<artifactId>gwt-libs</artifactId>
10
+		<version>4.1.0-SNAPSHOT</version>
11
+	</parent>
12
+	
13
+	<build>
14
+		<plugins>
15
+			<plugin>
16
+				<groupId>net.bluemind</groupId>
17
+				<artifactId>net.bluemind.codegen.gwt</artifactId>
18
+				<configuration>
19
+					<apiName>net.bluemind.attachment.api</apiName>
20
+				</configuration>
21
+				<executions>
22
+					<execution>
23
+						<goals>
24
+							<goal>gwt-gen</goal>
25
+						</goals>
26
+					</execution>
27
+				</executions>
28
+			</plugin>
29
+		</plugins>
30
+	</build>
31
+</project>
0 32
new file mode 100644
... ...
@@ -10,7 +10,8 @@ Require-Bundle: net.bluemind.core.commons.gwt;bundle-version="4.1.0",
10 10
  net.bluemind.tag.api.gwt;bundle-version="4.1.0";visibility:=reexport,
11 11
  net.bluemind.core.task.api.gwt;bundle-version="4.1.0";visibility:=reexport,
12 12
  com.google.gwt.user;resolution:=optional,
13
- net.bluemind.user.api.gwt;bundle-version="4.1.0";visibility:=reexport
13
+ net.bluemind.user.api.gwt;bundle-version="4.1.0";visibility:=reexport,
14
+ net.bluemind.attachment.api.gwt;bundle-version="4.1.0"
14 15
 Export-Package: net.bluemind.icalendar.api.gwt.js,
15 16
  net.bluemind.icalendar.api.gwt.serder
16 17
 
... ...
@@ -49,6 +49,7 @@
49 49
 		<module>net.bluemind.backend.mail.api.gwt</module>
50 50
 		<module>net.bluemind.monitoring.api.gwt</module>
51 51
         <module>net.bluemind.externaluser.api.gwt</module>
52
+        <module>net.bluemind.attachment.api.gwt</module>
52 53
 	</modules>
53 54
 
54 55
 	<build>