Skip to content

Commit 5c926e3

Browse files
Merge remote-tracking branch 'origin/maven/fixes/9.1' into maven/release/9.1
2 parents 166125f + 5079517 commit 5c926e3

File tree

47 files changed

+421
-146
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+421
-146
lines changed

Backend/alfresco/common/src/main/java/org/edu_sharing/repository/client/tools/CCConstants.java

+1
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ public enum PROPOSAL_STATUS {
911911

912912
public final static String CCM_VALUE_TOOLPERMISSION_GLOBAL_AUTHORITY_SEARCH_SHARE_SAFE = "TOOLPERMISSION_GLOBAL_AUTHORITY_SEARCH_SHARE_SAFE";
913913

914+
public final static String CCM_VALUE_TOOLPERMISSION_PREFIX = "TOOLPERMISSION_";
914915
public final static String CCM_VALUE_TOOLPERMISSION_CONNECTOR_PREFIX = "TOOLPERMISSION_CONNECTOR_";
915916

916917
public final static String CCM_VALUE_TOOLPERMISSION_REPOSITORY_PREFIX = "TOOLPERMISSION_REPOSITORY_";

Backend/alfresco/module/src/main/amp/config/alfresco/extension/es_models/ccmodel.xml

-1
Original file line numberDiff line numberDiff line change
@@ -2107,7 +2107,6 @@
21072107
<property name="ccm:wf_protocol">
21082108
<type>d:text</type>
21092109
<multiple>true</multiple>
2110-
<index enabled="false"/>
21112110
</property>
21122111
</properties>
21132112
</aspect>

Backend/alfresco/module/src/main/java/org/edu_sharing/alfresco/action/RessourceInfoExecuter.java

+55-15
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.apache.commons.compress.compressors.CompressorException;
2121
import org.apache.commons.compress.compressors.CompressorInputStream;
2222
import org.apache.commons.compress.compressors.CompressorStreamFactory;
23+
import org.apache.commons.lang3.StringUtils;
2324
import org.apache.commons.logging.Log;
2425
import org.apache.commons.logging.LogFactory;
2526
import org.apache.tika.Tika;
@@ -36,6 +37,7 @@
3637
import java.util.ArrayList;
3738
import java.util.Arrays;
3839
import java.util.List;
40+
import java.util.zip.ZipEntry;
3941

4042
@RequiredArgsConstructor
4143
public class RessourceInfoExecuter extends ActionExecuterAbstractBase {
@@ -64,13 +66,26 @@ public class RessourceInfoExecuter extends ActionExecuterAbstractBase {
6466
public static final String CCM_PROP_IO_RESOURCESUBTYPE = "{http://www.campuscontent.de/model/1.0}ccresourcesubtype";
6567
public static final String CCM_RESSOURCETYPE_MOODLE = "moodle";
6668
public static final String CCM_RESSOURCETYPE_H5P = "h5p";
69+
public static final String CCM_RESOURCESUBTYPE_ARTICULATE_STORYLINE = "Articulate Storyline";
70+
6771
// simple connector elements
6872
public static final String CCM_RESSOURCETYPE_CONNECTOR = "connector";
6973
public static final String CCM_RESSOURCETYPE_GEOGEBRA = "geogebra";
7074
public static final String CCM_RESSOURCETYPE_SERLO = "serlo";
7175
public static final String CCM_RESSOURCETYPE_EDUHTML = "eduhtml";
7276

73-
public static ArchiveInputStream getZipInputStream(ContentReader contentreader) throws IOException {
77+
static ArchiveEntry goToFileInZip(ArchiveInputStream zip, String name) throws IOException {
78+
while(true) {
79+
ArchiveEntry entry = zip.getNextEntry();
80+
if (entry == null)
81+
break;
82+
if (entry.getName().equals(name)) {
83+
return entry;
84+
}
85+
}
86+
return null;
87+
}
88+
public static ArchiveInputStream getZipInputStream(ContentReader contentreader) throws IOException {
7489
InputStream is = contentreader.getContentInputStream();
7590

7691
Tika tika = new Tika();
@@ -92,7 +107,7 @@ public static ArchiveInputStream getZipInputStream(ContentReader contentreader)
92107
logger.error(e.getMessage());
93108
}
94109
}else if(type.equals("application/zip")) {
95-
// allowStoredEntriesWithDataDescriptor = true because some h5p might have this
110+
// allowStoredEntriesWithDataDescriptor = true because some h5p might have this
96111
return new ZipArchiveInputStream(is, contentreader.getEncoding(), true, true);
97112
}else {
98113
logger.info("unknown format:" + type);
@@ -116,8 +131,12 @@ protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
116131
while ((current = zip.getNextEntry()) != null) {
117132
if (current.getName().equals("imsmanifest.xml")) {
118133

119-
process(zip, contentreader, actionedUponNodeRef);
134+
boolean isScorm = processScorm(zip, contentreader, actionedUponNodeRef);
120135
zip.close();
136+
if(isScorm) {
137+
contentreader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT);
138+
detectScormApplication(contentreader, actionedUponNodeRef);
139+
}
121140
return;
122141

123142
}
@@ -150,9 +169,9 @@ protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
150169
}
151170

152171
zip.close();
153-
if(genericHtmlFile != null){
154-
proccessGenericHTML(actionedUponNodeRef, genericHtmlFile);
155-
}
172+
if(genericHtmlFile != null){
173+
proccessGenericHTML(actionedUponNodeRef, genericHtmlFile);
174+
}
156175
} else {
157176
if(Arrays.asList("application/json", "text/plain", "application/octet-stream").contains(contentreader.getMimetype()) &&
158177
contentreader.getSize() < MAX_JSON_PARSE_SIZE) {
@@ -212,7 +231,7 @@ private void proccessGenericHTML(NodeRef nodeRef, String genericHtmlFile) {
212231
if(entry.getName().equals("Build/UnityLoader.js")){
213232

214233
nodeService.setProperty(nodeRef, QName.createQName(CCM_PROP_IO_RESOURCESUBTYPE),
215-
"webgl");
234+
"webgl");
216235
}
217236
}
218237
}
@@ -221,7 +240,7 @@ private void proccessGenericHTML(NodeRef nodeRef, String genericHtmlFile) {
221240
}
222241
}
223242

224-
private void process(InputStream is, ContentReader contentreader, NodeRef actionedUponNodeRef) {
243+
boolean processScorm(InputStream is, ContentReader contentreader, NodeRef actionedUponNodeRef) {
225244
Document doc = new RessourceInfoTool().loadFromStream(is);
226245
if ((contentreader.getMimetype().equals("application/zip")
227246
|| contentreader.getMimetype().equals("application/save-as")
@@ -263,9 +282,9 @@ private void process(InputStream is, ContentReader contentreader, NodeRef action
263282
ressourceType = schema;
264283
ressourceVersion = schemaVers;
265284
}
266-
285+
267286
if(ressourceType == null || ressourceType.trim().equals("")) {
268-
287+
269288
NodeList ns = (NodeList)xpath.evaluate("//manifest/@*", doc, XPathConstants.NODESET);
270289
for(int i = 0; i < ns.getLength(); i++) {
271290
if(ns.item(i) != null) {
@@ -277,9 +296,9 @@ private void process(InputStream is, ContentReader contentreader, NodeRef action
277296
}
278297
}
279298
}
280-
299+
281300
}
282-
301+
283302
logger.info("ressourceType:" + ressourceType);
284303
logger.info("ressourceVersion:" + ressourceVersion);
285304

@@ -338,12 +357,33 @@ private void process(InputStream is, ContentReader contentreader, NodeRef action
338357
} else {
339358
logger.info("thats no qti!!!!!");
340359
}
360+
return ressourceType != null;
341361

342362
} catch (Exception e) {
343363
e.printStackTrace();
344364
}
345365
}
366+
return false;
367+
}
368+
369+
void detectScormApplication(ContentReader contentreader, NodeRef actionedUponNodeRef) {
370+
try (ArchiveInputStream zip = getZipInputStream(contentreader)) {
371+
ArchiveEntry meta = goToFileInZip(zip, "meta.xml");
372+
if(meta != null) {
373+
Document metaDoc = new RessourceInfoTool().loadFromStream(zip);
374+
XPath xpath = XPathFactory.newInstance().newXPath();
375+
String appName = (String) xpath.evaluate("/meta/project/application/@name", metaDoc, XPathConstants.STRING);
376+
if(StringUtils.isNotEmpty(appName)) {
377+
nodeService.setProperty(actionedUponNodeRef, QName.createQName(CCM_PROP_IO_RESOURCESUBTYPE),
378+
appName);
379+
}
380+
381+
}
382+
} catch(Throwable t) {
383+
logger.warn(t);
384+
}
346385
}
386+
347387
void processGeogebra(InputStream is, NodeRef actionedUponNodeRef) {
348388
// thumbnail is handled @org.edu_sharing.alfresco.transformer.GeogebraTransformerWorker
349389
try {
@@ -354,7 +394,7 @@ void processGeogebra(InputStream is, NodeRef actionedUponNodeRef) {
354394
String schemaVers = (String) xpath.evaluate(schemaVersPath, doc, XPathConstants.STRING);
355395
if (schemaVers != null && !schemaVers.equals("")) {
356396
if (!this.nodeService.hasAspect(actionedUponNodeRef,
357-
QName.createQName(CCM_ASPECT_RESSOURCEINFO))) {
397+
QName.createQName(CCM_ASPECT_RESSOURCEINFO))) {
358398
this.nodeService.addAspect(actionedUponNodeRef, QName.createQName(CCM_ASPECT_RESSOURCEINFO),
359399
null);
360400
}
@@ -451,7 +491,7 @@ public static void main(String[] args) {
451491
Tika tika = new Tika();
452492
String type = tika.detect(fis);
453493
System.out.println("type:" + type);
454-
494+
455495
final InputStream is = new BufferedInputStream(fis);
456496
// CompressorInputStream in = new
457497
// CompressorStreamFactory().createCompressorInputStream("bzip2", is);
@@ -476,7 +516,7 @@ public static void main(String[] args) {
476516
tais.close();
477517
in.close();
478518
}
479-
519+
480520
} catch (FileNotFoundException e) {
481521
// TODO Auto-generated catch block
482522
e.printStackTrace();

Backend/alfresco/module/src/main/java/org/edu_sharing/alfresco/service/toolpermission/ToolPermissionBaseService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public List<String> doWork() throws Exception {
185185
public List<String> getAllAvailableToolPermissions(){
186186
return getAllAvailableToolPermissions(false);
187187
}
188-
public List<String> getAllAvailableToolPermissions(boolean renew){
188+
private List<String> getAllAvailableToolPermissions(boolean renew){
189189
List<String> allowed=new ArrayList<>();
190190
for(String permission : this.getAllToolPermissions(renew)){
191191
if(hasToolPermission(permission, renew))

Backend/alfresco/module/src/test/java/org/edu_sharing/alfresco/action/RessourceInfoExecuterTest.java

+36-1
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,23 @@
33
import com.google.gson.Gson;
44
import com.google.gson.GsonBuilder;
55
import com.google.gson.LongSerializationPolicy;
6+
import org.alfresco.service.cmr.repository.ContentReader;
67
import org.alfresco.service.cmr.repository.NodeRef;
78
import org.alfresco.service.cmr.repository.NodeService;
89
import org.alfresco.service.cmr.repository.StoreRef;
910
import org.alfresco.service.namespace.QName;
11+
import org.apache.commons.compress.archivers.ArchiveEntry;
12+
import org.apache.commons.compress.archivers.ArchiveInputStream;
1013
import org.edu_sharing.alfresco.lightbend.LightbendConfigCache;
1114
import org.edu_sharing.alfresco.lightbend.LightbendConfigLoader;
15+
import org.edu_sharing.repository.client.tools.CCConstants;
1216
import org.junit.jupiter.api.Assertions;
1317
import org.junit.jupiter.api.BeforeEach;
1418
import org.junit.jupiter.api.Test;
19+
import org.mockito.Mock;
1520
import org.mockito.Mockito;
1621

17-
import java.io.ByteArrayInputStream;
22+
import java.io.*;
1823
import java.util.HashMap;
1924
import java.util.UUID;
2025

@@ -70,4 +75,34 @@ void processSerloTest() {
7075
Mockito.reset(mockedNodeService);
7176

7277
}
78+
79+
@Test
80+
void processScormTest() throws IOException {
81+
NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, UUID.randomUUID().toString());
82+
ContentReader contentReader = Mockito.mock(ContentReader.class);
83+
Mockito.doReturn("application/zip").when(contentReader).getMimetype();
84+
Mockito.doReturn("UTF-8").when(contentReader).getEncoding();
85+
Mockito.doAnswer(invocationOnMock -> new BufferedInputStream(new FileInputStream(getClass().getClassLoader().getResource("Articulate_Storyline_Scorm.zip").getFile()))).when(contentReader).getContentInputStream();
86+
87+
ArchiveInputStream zip = RessourceInfoExecuter.getZipInputStream(contentReader);
88+
if(RessourceInfoExecuter.goToFileInZip(zip, "imsmanifest.xml") != null) {
89+
Assertions.assertTrue(underTest.processScorm(zip, contentReader, nodeRef));
90+
underTest.detectScormApplication(contentReader, nodeRef);
91+
Mockito.verify(mockedNodeService, times(1)).addAspect(nodeRef, QName.createQName(RessourceInfoExecuter.CCM_ASPECT_RESSOURCEINFO), null);
92+
Mockito.verify(mockedNodeService, times(1)).setProperty(nodeRef, QName.createQName(RessourceInfoExecuter.CCM_PROP_IO_RESSOURCETYPE), "ADL SCORM");
93+
Mockito.verify(mockedNodeService, times(1)).setProperty(nodeRef, QName.createQName(CCConstants.CCM_PROP_CCRESSOURCE_MAIN_ENTITY), "index_lms.html");
94+
Mockito.verify(mockedNodeService, times(1)).setProperty(nodeRef, QName.createQName(RessourceInfoExecuter.CCM_PROP_IO_RESOURCESUBTYPE), RessourceInfoExecuter.CCM_RESOURCESUBTYPE_ARTICULATE_STORYLINE);
95+
Mockito.verify(mockedNodeService, times(1)).setProperty(nodeRef, QName.createQName(RessourceInfoExecuter.CCM_PROP_IO_RESSOURCEVERSION), "1.2");
96+
} else {
97+
Assertions.fail("scorm xml not found");
98+
}
99+
100+
while(true) {
101+
ArchiveEntry entry = zip.getNextEntry();
102+
if (entry == null)
103+
break;
104+
if (entry.getName().equals("imsmanifest.xml")) {
105+
}
106+
}
107+
}
73108
}
Binary file not shown.

Backend/services/core/src/main/java/org/edu_sharing/repository/server/AuthenticationToolAPI.java

-5
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,6 @@ public void storeAuthInfoInSession(String username, String ticket, String authTy
233233
//i.e jession with ticket + basic auth in ApiAuthenticationFilter
234234
authenticationService.validate(ticket);
235235

236-
// prewarm tp session cache
237-
// not required since validateSession will do it anyway
238-
// otherwise, every status probe call will build unnecessary a tp cache
239-
//ToolPermissionServiceFactory.getInstance().getAllAvailableToolPermissions();
240-
241236
try {
242237
Map<String, String> userInfo = getUserInfo(authenticationService.getCurrentUserName(), ticket);
243238
session.setAttribute(CCConstants.AUTH_USERNAME_CAPTION, userInfo.get(CCConstants.AUTH_USERNAME_CAPTION));

Backend/services/core/src/main/java/org/edu_sharing/repository/server/DownloadServlet.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jakarta.servlet.http.HttpServlet;
66
import jakarta.servlet.http.HttpServletRequest;
77
import jakarta.servlet.http.HttpServletResponse;
8+
import lombok.SneakyThrows;
89
import org.alfresco.model.ContentModel;
910
import org.alfresco.repo.security.authentication.AuthenticationUtil;
1011
import org.alfresco.service.cmr.repository.NodeRef;
@@ -51,7 +52,8 @@ public class DownloadServlet extends HttpServlet {
5152
private static PermissionChecking permissionChecking;
5253
static Logger logger = Logger.getLogger(DownloadServlet.class);
5354

54-
@Override
55+
@SneakyThrows
56+
@Override
5557
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
5658
throws ServletException, IOException {
5759
if(permissionChecking == null) {
@@ -235,7 +237,7 @@ private static String checkAndGetCollectionRef(String nodeId) throws Insufficien
235237
return null;
236238
}
237239

238-
public static void downloadZip(HttpServletResponse resp, String[] nodeIds, String parentNodeId, String token, String password, String zipName) throws IOException {
240+
public static void downloadZip(HttpServletResponse resp, String[] nodeIds, String parentNodeId, String token, String password, String zipName) throws Exception {
239241
if(zipName==null || zipName.isEmpty())
240242
zipName="Download.zip";
241243

@@ -359,6 +361,7 @@ public static void downloadZip(HttpServletResponse resp, String[] nodeIds, Strin
359361
}
360362
catch(Throwable t){
361363
t.printStackTrace();
364+
throw t;
362365
}
363366
}
364367

Backend/services/core/src/main/java/org/edu_sharing/repository/server/authentication/AuthenticationFilter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
103103
//if its APIClient user name is ignored and is figured out with authentication service
104104

105105
// Force a renew of all toolpermissions since they might have now changed!
106-
ToolPermissionServiceFactory.getInstance().getAllAvailableToolPermissions(true);
106+
ToolPermissionServiceFactory.getInstance().invalidateSessionCache();
107107
/**
108108
* auth type ticket means no profile editing allowed,
109109
* authenticated by an lms or other connected system that

Backend/services/core/src/main/java/org/edu_sharing/repository/server/authentication/GuestFilter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
8181
authTool.storeAuthInfoInSession(authInfoGuest.get(CCConstants.AUTH_USERNAME), authInfoGuest.get(CCConstants.AUTH_TICKET), CCConstants.AUTH_TYPE_DEFAULT, session);
8282

8383
// prewarm tp session cache
84-
ToolPermissionServiceFactory.getInstance().getAllAvailableToolPermissions();
84+
ToolPermissionServiceFactory.getInstance().invalidateSessionCache();
8585
}
8686
} else {
8787
logger.debug("no guest defined");

Backend/services/core/src/main/java/org/edu_sharing/restservices/ApiAuthenticationFilter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public void doFilter(ServletRequest req, ServletResponse resp,
9999
String ticket = authHdr.substring(10).trim();
100100
if (authTool.validateTicket(ticket)) {
101101
// Force a renew of all toolpermissions since they might have now changed!
102-
ToolPermissionServiceFactory.getInstance().getAllAvailableToolPermissions(true);
102+
ToolPermissionServiceFactory.getInstance().invalidateSessionCache();
103103
//if its APIClient username is ignored and is figured out with authentication service
104104
authTool.storeAuthInfoInSession(authTool.getCurrentUser(), ticket, CCConstants.AUTH_TYPE_TICKET, httpReq.getSession());
105105
validatedAuth = authTool.validateAuthentication(session);

Backend/services/core/src/main/java/org/edu_sharing/service/admin/AdminServiceImpl.java

+1
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,7 @@ public List<JobDescription> getJobDescriptions(boolean fetchAbstractJobs) {
11081108
@Override
11091109
public void switchAuthentication(String authorityName) {
11101110
HttpSession session = Context.getCurrentInstance().getRequest().getSession(true);
1111+
ToolPermissionServiceFactory.getInstance().invalidateSessionCache();
11111112
//session.setMaxInactiveInterval(30);
11121113
AuthenticationToolAPI authTool = new AuthenticationToolAPI();
11131114
String ticket = authTool.setUser(authorityName);

0 commit comments

Comments
 (0)