Merge remote-tracking branch 'origin/main'

This commit is contained in:
Maximilian Kratz 2024-09-11 09:32:17 +02:00
commit 144c5b75b3
77 changed files with 2826 additions and 413 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 93 KiB

View file

@ -126,6 +126,37 @@
<version>3.8.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client</artifactId>
<version>1.34.1</version>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-jetty</artifactId>
<version>1.34.1</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.12.610</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>aws-sdk-java</artifactId>
<version>2.21.45</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.20.52</version>
</dependency>
</dependencies>
<parent>

View file

@ -1,5 +1,8 @@
package moodle.sync.core.config;
import moodle.sync.core.fileserver.FileServerType;
import moodle.sync.core.fileserver.LanguageSupport;
import java.util.Locale;
/**
@ -15,10 +18,14 @@ public class DefaultConfiguration extends MoodleSyncConfiguration {
setStartMaximized(false);
setAdvancedUIMode(false);
setSyncRootPath(System.getProperty("user.dir"));
setFormatsFileserver("");
setFormatsMoodle("pdf,png,pptx,docx");
setPortFileserver("21");
setMoodleUrl("https://localhost");
setFormatsMoodle("pdf,png,pptx,docx");
setRecentFileServerType(LanguageSupport.getDefaultFileserver(Locale.getDefault()));
setFtpConfiguration(new FileserverFTPConfiguration());
getFtpConfiguration().setFtpFormats("avi,mp4,mpg,wmv,mov");
setPanoptoConfiguration(new FileserverPanoptoConfiguration());
getPanoptoConfiguration().setPanoptoFormats("avi,mp4,mpg,wmv,mov");
getFtpConfiguration().setFtpPort("21");
}
}

View file

@ -0,0 +1,112 @@
package moodle.sync.core.config;
import moodle.sync.core.beans.StringProperty;
import java.util.Objects;
public class FileserverFTPConfiguration {
//The Url of the fileserver.
private final StringProperty ftpServer = new StringProperty();
//The users fileserver-username.
private final StringProperty ftpUser = new StringProperty();
//The users fileserver-password.
private final StringProperty ftpPassword = new StringProperty();
//The choosen port for the fileserver-communication.
private final StringProperty ftpPort = new StringProperty();
//If a file belongs to this format, it should be synchronized with the fileserver.
private final StringProperty ftpFormats = new StringProperty();
public FileserverFTPConfiguration() {
this.ftpServer.set("");
this.ftpUser.set("");
this.ftpPassword.set("");
this.ftpPort.set("");
this.ftpFormats.set("");
}
public FileserverFTPConfiguration (FileserverFTPConfiguration config) {
this.ftpServer.set(config.ftpServer.get());
this.ftpUser.set(config.ftpUser.get());
this.ftpPassword.set(config.ftpPassword.get());
this.ftpPort.set(config.ftpPort.get());
this.ftpFormats.set(config.ftpFormats.get());
}
public String getFtpServer() {
return ftpServer.get();
}
public void setFtpServer(String fileserver) {
this.ftpServer.set(fileserver);
}
public StringProperty ftpServerProperty() {
return ftpServer;
}
public String getFtpUser() {
return ftpUser.get();
}
public void setFtpUser(String user) {
this.ftpUser.set(user);
}
public StringProperty ftpUserProperty() {
return ftpUser;
}
public String getFtpPassword() {
return ftpPassword.get();
}
public void setFtpPassword(String formats) {
this.ftpPassword.set(formats);
}
public StringProperty ftpPasswordProperty() {
return ftpPassword;
}
public String getFtpPort() {
return ftpPort.get();
}
public void setFtpPort(String port) {
this.ftpPort.set(port);
}
public StringProperty ftpPortProperty() {
return ftpPort;
}
public String getFtpFormats() {
return ftpFormats.get();
}
public void setFtpFormats(String formats) {
this.ftpFormats.set(formats);
}
public StringProperty ftpFormatsProperty() {
return ftpFormats;
}
@Override
public int hashCode() {
return Objects.hash(ftpServer, ftpUser, ftpPassword, ftpPort, ftpFormats);
}
public boolean equals(FileserverFTPConfiguration o) {
return Objects.equals(this.ftpServer.get(), o.ftpServer.get()) &&
Objects.equals(this.ftpUser.get(), o.ftpUser.get()) &&
Objects.equals(this.ftpPassword.get(), o.ftpPassword.get()) &&
Objects.equals(this.ftpPort.get(), o.ftpPort.get()) &&
Objects.equals(this.ftpFormats.get(), o.ftpFormats.get());
}
}

View file

@ -0,0 +1,130 @@
package moodle.sync.core.config;
import moodle.sync.core.beans.ObjectProperty;
import moodle.sync.core.beans.StringProperty;
import moodle.sync.core.model.json.PanoptoCourse;
import java.util.Objects;
public class FileserverPanoptoConfiguration {
//The Url of the fileserver.
private final StringProperty panoptoServer = new StringProperty();
//The users fileserver-username.
private final StringProperty panoptoClientId = new StringProperty();
//The users fileserver-password.
private final StringProperty panoptoSecret = new StringProperty();
private final StringProperty panoptoDefaultFolder = new StringProperty();
//If a file belongs to this format, it should be synchronized with the fileserver.
private final StringProperty panoptoFormats = new StringProperty();
private final ObjectProperty<PanoptoCourse> panoptoCourse = new ObjectProperty<>();
public FileserverPanoptoConfiguration() {
this.panoptoServer.set("");
this.panoptoClientId.set("");
this.panoptoSecret.set("");
this.panoptoDefaultFolder.set("");
this.panoptoFormats.set("");
this.panoptoCourse.set(new PanoptoCourse());
}
public FileserverPanoptoConfiguration (FileserverPanoptoConfiguration config) {
this.panoptoServer.set(config.panoptoServer.get());
this.panoptoClientId.set(config.panoptoClientId.get());
this.panoptoSecret.set(config.panoptoSecret.get());
this.panoptoDefaultFolder.set(config.panoptoDefaultFolder.get());
this.panoptoFormats.set(config.panoptoFormats.get());
this.panoptoCourse.set(config.panoptoCourse.get());
}
public String getPanoptoServer() {
return panoptoServer.get();
}
public void setPanoptoServer(String fileserver) {
this.panoptoServer.set(fileserver);
}
public StringProperty panoptoServerProperty() {
return panoptoServer;
}
public String getPanoptoClientId() {
return panoptoClientId.get();
}
public void setPanoptoClientId(String user) {
this.panoptoClientId.set(user);
}
public StringProperty panoptoClientIdProperty() {
return panoptoClientId;
}
public String getPanoptoSecret() {
return panoptoSecret.get();
}
public void setPanoptoSecret(String formats) {
this.panoptoSecret.set(formats);
}
public StringProperty panoptoSecretProperty() {
return panoptoSecret;
}
public String getPanoptoDefaultFolder() {
return panoptoDefaultFolder.get();
}
public void setPanoptoDefaultFolder(String folder) {
this.panoptoDefaultFolder.set(folder);
}
public StringProperty panoptoDefaultFolderProperty() {
return panoptoDefaultFolder;
}
public String getPanoptoFormats() {
return panoptoFormats.get();
}
public void setPanoptoFormats(String formats) {
this.panoptoFormats.set(formats);
}
public StringProperty panoptoFormatsProperty() {
return panoptoFormats;
}
public PanoptoCourse getPanoptoCourse() {
return panoptoCourse.get();
}
public void setPanoptoCourse(PanoptoCourse panoptoCourse) {
this.panoptoCourse.set(panoptoCourse);
}
public ObjectProperty<PanoptoCourse> panoptoCourseProperty() {
return panoptoCourse;
}
@Override
public int hashCode() {
return Objects.hash(panoptoServer, panoptoClientId, panoptoSecret, panoptoDefaultFolder, panoptoFormats, panoptoCourse);
}
public boolean equals(FileserverPanoptoConfiguration o) {
return Objects.equals(this.panoptoServer.get(), o.panoptoServer.get()) &&
Objects.equals(this.panoptoClientId.get(), o.panoptoClientId.get()) &&
Objects.equals(this.panoptoSecret.get(), o.panoptoSecret.get()) &&
Objects.equals(this.panoptoDefaultFolder.get(), o.panoptoDefaultFolder.get()) &&
Objects.equals(this.panoptoFormats.get(), o.panoptoFormats.get()) &&
Objects.equals(this.panoptoCourse.get(), o.panoptoCourse.get());
}
}

View file

@ -16,6 +16,9 @@ import java.util.Objects;
*/
public class MoodleSyncConfiguration extends Configuration {
//Language
private final ObjectProperty<Locale> locale = new ObjectProperty<>();
//The path where the synchronized files are stored at.
private final StringProperty syncRootPath = new StringProperty();
@ -34,45 +37,33 @@ public class MoodleSyncConfiguration extends Configuration {
//If a file belongs to this format, it should be synchronized with the Moodle-plattform.
private final StringProperty formatsMoodle = new StringProperty();
//If a file belongs to this format, it should be synchronized with the fileserver.
private final StringProperty formatsFileserver = new StringProperty();
private final StringProperty fileServerType = new StringProperty();
//The Url of the fileserver.
private final StringProperty ftpserver = new StringProperty();
private final ObjectProperty<FileserverFTPConfiguration> ftpConfiguration = new ObjectProperty<>();
//The users fileserver-username.
private final StringProperty ftpuser = new StringProperty();
//The users fileserver-password.
private final StringProperty ftppassword = new StringProperty();
//The choosen port for the fileserver-communication.
private final StringProperty ftpport = new StringProperty();
private final ObjectProperty<FileserverPanoptoConfiguration> panoptoConfiguration = new ObjectProperty<>();
//Whether files of unknown fileformat should be displayed.
private final BooleanProperty showUnknownFormats = new BooleanProperty();
//Language
private final ObjectProperty<Locale> locale = new ObjectProperty<>();
public MoodleSyncConfiguration() {
}
public MoodleSyncConfiguration (MoodleSyncConfiguration config) {
this.locale.set(config.locale.get());
this.syncRootPath.set(config.syncRootPath.get());
this.recentCourse.set(config.recentCourse.get());
this.moodleToken.set(config.moodleToken.get());
this.recentSection.set(config.recentSection.get());
this.moodleUrl.set(config.moodleUrl.get());
this.formatsMoodle.set(config.formatsMoodle.get());
this.formatsFileserver.set(config.formatsFileserver.get());
this.ftpserver.set(config.ftpserver.get());
this.ftpuser.set(config.ftpuser.get());
this.ftppassword.set(config.ftppassword.get());
this.ftpport.set(config.ftpport.get());
this.fileServerType.set(config.fileServerType.get());
this.ftpConfiguration.set(new FileserverFTPConfiguration(config.ftpConfiguration.get()));
this.panoptoConfiguration.set(new FileserverPanoptoConfiguration(config.panoptoConfiguration.get()));
this.showUnknownFormats.set(config.showUnknownFormats.get());
this.locale.set(config.locale.get());
}
public String getSyncRootPath() {
@ -147,64 +138,40 @@ public class MoodleSyncConfiguration extends Configuration {
return formatsMoodle;
}
public String getFormatsFileserver() {
return formatsFileserver.get();
public String getFileServerType() {
return fileServerType.get();
}
public void setFormatsFileserver(String formats) {
this.formatsFileserver.set(formats);
public void setRecentFileServerType(String fileServerType) {
this.fileServerType.set(fileServerType);
}
public StringProperty formatsFileserverProperty() {
return formatsFileserver;
public StringProperty fileServerTypeProperty() {
return fileServerType;
}
public String getFileserver() {
return ftpserver.get();
public FileserverFTPConfiguration getFtpConfiguration() {
return ftpConfiguration.get();
}
public void setFileserver(String fileserver) {
this.ftpserver.set(fileserver);
public void setFtpConfiguration(FileserverFTPConfiguration ftpConfiguration) {
this.ftpConfiguration.set(ftpConfiguration);
}
public StringProperty FileserverProperty() {
return ftpserver;
public ObjectProperty<FileserverFTPConfiguration> FtpConfigurationProperty() {
return ftpConfiguration;
}
public String getUserFileserver() {
return ftpuser.get();
public FileserverPanoptoConfiguration getPanoptoConfiguration() {
return panoptoConfiguration.get();
}
public void setUserFileserver(String user) {
this.ftpuser.set(user);
public void setPanoptoConfiguration(FileserverPanoptoConfiguration panoptoConfiguration) {
this.panoptoConfiguration.set(panoptoConfiguration);
}
public StringProperty userFileserverProperty() {
return ftpuser;
}
public String getPasswordFileserver() {
return ftppassword.get();
}
public void setPasswordFileserver(String formats) {
this.ftppassword.set(formats);
}
public StringProperty passwordFileserverProperty() {
return ftppassword;
}
public String getPortFileserver() {
return ftpport.get();
}
public void setPortFileserver(String port) {
this.ftpport.set(port);
}
public StringProperty portFileserverProperty() {
return ftpport;
public ObjectProperty<FileserverPanoptoConfiguration> PanoptoConfigurationProperty() {
return panoptoConfiguration;
}
public Boolean getShowUnknownFormats() {
@ -232,16 +199,15 @@ public class MoodleSyncConfiguration extends Configuration {
}
public boolean equals(MoodleSyncConfiguration o) {
return Objects.equals(this.syncRootPath.get(), o.syncRootPath.get()) && Objects.equals(this.recentCourse.get(),
o.recentCourse.get()) && Objects.equals(this.moodleToken.get(), o.moodleToken.get()) &&
return Objects.equals(this.syncRootPath.get(), o.syncRootPath.get()) &&
Objects.equals(this.recentCourse.get(), o.recentCourse.get()) &&
Objects.equals(this.moodleToken.get(), o.moodleToken.get()) &&
Objects.equals(this.recentSection.get(), o.recentSection.get()) &&
Objects.equals(this.moodleUrl.get(), o.moodleUrl.get()) &&
Objects.equals(this.formatsMoodle.get(), o.formatsMoodle.get()) &&
Objects.equals(this.formatsFileserver.get(), o.formatsFileserver.get()) &&
Objects.equals(this.ftpserver.get(), o.ftpserver.get()) &&
Objects.equals(this.ftpuser.get(), o.ftpuser.get()) &&
Objects.equals(this.ftppassword.get(), o.ftppassword.get()) &&
Objects.equals(this.ftpport.get(), o.ftpport.get()) &&
Objects.equals(this.fileServerType.get(), o.fileServerType.get()) &&
(this.ftpConfiguration.get().equals(o.ftpConfiguration.get())) &&
(this.panoptoConfiguration.get().equals(o.panoptoConfiguration.get())) &&
Objects.equals(this.showUnknownFormats.get(), o.showUnknownFormats.get()) &&
Objects.equals(this.locale.get(), o.locale.get());
}
@ -249,7 +215,7 @@ public class MoodleSyncConfiguration extends Configuration {
@Override
public int hashCode() {
return Objects.hash(syncRootPath, recentCourse, moodleToken, recentSection, moodleUrl, formatsMoodle,
formatsFileserver, ftpserver, ftpuser, ftppassword, ftpport, showUnknownFormats, locale);
ftpConfiguration, panoptoConfiguration, showUnknownFormats, locale);
}
}

View file

@ -9,6 +9,7 @@ import java.util.List;
*/
public interface FileServerClient {
String getName();
//Retrieve list of FileServerFiles from dedicated directory
List<FileServerFile> getFiles(String pathname) throws Exception;

View file

@ -8,6 +8,7 @@ import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import javax.ws.rs.Path;
import java.io.IOException;
import java.io.PrintWriter;
@ -41,13 +42,14 @@ public class FileServerClientFTP implements FileServerClient {
@Override
public void connect() {
try {
ftpClient.connect(config.getFileserver(), Integer.parseInt(config.getPortFileserver()));
ftpClient.connect(config.getFtpConfiguration().getFtpServer(),
Integer.parseInt(config.getFtpConfiguration().getFtpPort()));
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
throw new IOException("Exception in connecting to FTP Server");
}
ftpClient.login(config.getUserFileserver(), config.getPasswordFileserver());
ftpClient.login(config.getFtpConfiguration().getFtpUser(), config.getFtpConfiguration().getFtpPassword());
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
}
catch (IOException e) {
@ -89,6 +91,12 @@ public class FileServerClientFTP implements FileServerClient {
return files;
}
@Override
public String getName() {
//Todo With Language-Support
return "FTP-Server";
}
/**
* Method to upload a file to a ftpserver.
*

View file

@ -0,0 +1,14 @@
package moodle.sync.core.fileserver;
import java.io.Serializable;
public enum FileServerType implements Serializable {
FTP,
Panopto;
FileServerType() {};
}

View file

@ -0,0 +1,14 @@
package moodle.sync.core.fileserver;
import java.util.Locale;
public class LanguageSupport {
public static String getDefaultFileserver(Locale locale) {
if(locale.equals(Locale.GERMAN) || locale.equals(Locale.GERMANY)) {
return "Keiner";
} else {
return "None";
}
}
}

View file

@ -0,0 +1,9 @@
package moodle.sync.core.fileserver.ftp;
public class FtpException extends Exception{
public FtpException() {
super();
}
}

View file

@ -0,0 +1,8 @@
package moodle.sync.core.fileserver.panopto;
public class PanoptoException extends Exception {
public PanoptoException() {
super();
}
}

View file

@ -0,0 +1,197 @@
package moodle.sync.core.fileserver.panopto;
import moodle.sync.core.fileserver.panopto.util.XMLWriter;
import moodle.sync.core.model.json.PanoptoFolder;
import moodle.sync.core.model.json.PanoptoSession;
import moodle.sync.core.model.json.PanoptoSessionComplete;
import moodle.sync.core.web.model.TokenProvider;
import moodle.sync.core.web.panopto.PanoptoService;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
import java.io.RandomAccessFile;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class PanoptoUploader {
private static S3Client s3;
public static String uploadVideo (PanoptoService panoptoService, String uri, String folderId, Path path,
String title,
String description) throws PanoptoException {
try {
PanoptoSession session = panoptoService.setBlankSession(new PanoptoFolder(folderId));
String[] uploadTarget = session.getUploadTarget().split("/");
String bucketName = uploadTarget[4];
String filename = String.valueOf(path.getFileName());
String key1 = uploadTarget[5] + "/" + filename;
String key2 = uploadTarget[5] + "/upload_manifest_generated.xml";
URI myURI = new URI(uri + "/Panopto");
System.setProperty("aws.accessKeyId", "dummy");
System.setProperty("aws.secretAccessKey", "dummy");
uploadSingleFile(bucketName, key1, myURI, path);
uploadSingleFile(bucketName, key2, myURI, XMLWriter.CreateUpload_manifest(title, description, getZoneDateTime(), filename));
PanoptoSessionComplete sessionComplete = new PanoptoSessionComplete(session.getID(), session.getUploadTarget(), session.getFolderId(), "1", session.getSessionId());
panoptoService.setFinishSession(sessionComplete);
return session.getID();
}
catch (Exception e) {
throw new PanoptoException();
}
}
private static void uploadSingleFile(String bucketName, String key, URI myURI, Path path) throws Exception{
s3 = S3Client.builder().region(Region.EU_CENTRAL_1).endpointOverride(myURI).build();
CreateMultipartUploadRequest createRequest =
CreateMultipartUploadRequest.builder().bucket(bucketName).key(key).build();
CreateMultipartUploadResponse createResponse = s3.createMultipartUpload(createRequest);
String uploadId = createResponse.uploadId();
//If file is larger than 25 MB, the panopto server may fail, so the file is split up in several parts.
List<CompletedPart> completedParts = new ArrayList<>();
int partNumber = 1;
ByteBuffer buffer = ByteBuffer.allocate(10 * 1024 * 1024);
RandomAccessFile file = new RandomAccessFile(path.toFile(), "r");
long fileSize = file.length();
long position = 0;
while (position < fileSize) {
file.seek(position);
int bytesRead = file.getChannel().read(buffer);
buffer.flip();
UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
.bucket(bucketName)
.key(key)
.uploadId(uploadId)
.partNumber(partNumber)
.contentLength((long) bytesRead)
.build();
UploadPartResponse response = s3.uploadPart(uploadPartRequest, RequestBody.fromByteBuffer(buffer));
completedParts.add(CompletedPart.builder()
.partNumber(partNumber)
.eTag(response.eTag())
.build());
buffer.clear();
position += bytesRead;
partNumber++;
}
CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder()
.parts(completedParts)
.build();
CompleteMultipartUploadRequest completeMultipartUploadRequest =
CompleteMultipartUploadRequest.builder()
.bucket(bucketName)
.key(key)
.uploadId(uploadId)
.multipartUpload(completedMultipartUpload)
.build();
s3.completeMultipartUpload(completeMultipartUploadRequest);
}
private static void uploadSingleFile(String bucketName, String key, URI myURI, byte[] file) {
s3 = S3Client.builder().region(Region.EU_CENTRAL_1).endpointOverride(myURI).build();
CreateMultipartUploadRequest createRequest =
CreateMultipartUploadRequest.builder().bucket(bucketName).key(key).build();
CreateMultipartUploadResponse createResponse = s3.createMultipartUpload(createRequest);
String uploadId = createResponse.uploadId();
UploadPartRequest uploadPartRequest1 = UploadPartRequest.builder()
.bucket(bucketName)
.key(key)
.uploadId(uploadId)
.partNumber(1).build();
String etag1 = s3.uploadPart(uploadPartRequest1, RequestBody.fromBytes(file)).eTag();
CompletedPart part1 = CompletedPart.builder().partNumber(1).eTag(etag1).build();
CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder()
.parts(part1)
.build();
CompleteMultipartUploadRequest completeMultipartUploadRequest =
CompleteMultipartUploadRequest.builder()
.bucket(bucketName)
.key(key)
.uploadId(uploadId)
.multipartUpload(completedMultipartUpload)
.build();
s3.completeMultipartUpload(completeMultipartUploadRequest);
}
private static String getZoneDateTime() {
/*SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat format2 = new SimpleDateFormat("HH:mm:ss");
StringBuffer buff = new StringBuffer();
Date date = new Date();
buff.append(format1.format(date));
buff.append('T');
buff.append(format2.format(date));
Calendar calendar = Calendar.getInstance();*/
//int offset = calendar.get(calendar.ZONE_OFFSET)
/// (1000 * 60);
//TODO look into this
/*int offset = 0;
if (offset < 0) {
buff.append('-');
offset *= -1;
}
else {
buff.append('+');
}
String s1 = String.valueOf(offset / 60);
for (int i = s1.length(); i < 2; i++) {
buff.append('0');
}
buff.append(s1);
buff.append(':');
String s2 = String.valueOf(offset % 60);
for (int i = s2.length(); i < 2; i++) {
buff.append('0');
}
buff.append(s2);
System.out.println(buff.toString());
System.out.println(OffsetDateTime.now( ZoneOffset.UTC ));
//return buff.toString();*/
return OffsetDateTime.now( ZoneOffset.UTC ).toString();
}
}

View file

@ -0,0 +1,156 @@
package moodle.sync.core.fileserver.panopto.util;
import com.google.api.client.auth.oauth2.*;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.store.DataStore;
import com.google.api.client.util.store.DataStoreFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import moodle.sync.core.app.ApplicationContext;
import moodle.sync.core.config.MoodleSyncConfiguration;
import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class PanoptoAuthorizer {
private final MoodleSyncConfiguration config;
//TODO make this a variable from Config
private static final String TOKEN_SERVER_URL = "https://tu-darmstadt.cloud.panopto.eu/Panopto/oauth2/connect/token";
private static final String AUTHORIZATION_SERVER_URL = "https://tu-darmstadt.cloud.panopto.eu/Panopto/oauth2/connect/authorize";
/** Port in the "Callback URL". */
private static final int PORT = 9127;
/** Domain name in the "Callback URL". */
private static final String DOMAIN = "localhost";
/**
* Directory to store user credentials.
*/
private static File DATA_STORE_DIR = new File(System.getProperty("user.home"), ".store/googlesample");
/**
* Global instance of the {@link DataStoreFactory}. The best practice is to make it a single
* globally shared instance across your application.
*/
public static FileDataStoreFactory DATA_STORE_FACTORY;
private static DataStore<StoredCredential> credentialDataStore;
/**
* OAuth 2 scope.
*/
private static final List<String> SCOPE =
Arrays.asList("openid", "api" , "offline_access");
/**
* Global instance of the HTTP transport.
*/
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/**
* Global instance of the JSON factory.
*/
static final JsonFactory JSON_FACTORY = new GsonFactory();
@Inject
public PanoptoAuthorizer(ApplicationContext context){
this.config = (MoodleSyncConfiguration) context.getConfiguration();
}
/**
* Method used to authorize a user via OAuth2.
*
* @return Credentials
* @throws IOException
*/
public static Credential fullAuthorize(String apiKey, String apiSecret) throws IOException {
new File(System.getProperty("user.home"), ".store/googlesample/StoredCredential").delete();
DATA_STORE_DIR = new File(System.getProperty("user.home"), ".store/googlesample");
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
// set up authorization code flow
AuthorizationCodeFlow flow = new AuthorizationCodeFlow.Builder(BearerToken.authorizationHeaderAccessMethod(),
HTTP_TRANSPORT, JSON_FACTORY, new GenericUrl(TOKEN_SERVER_URL),
new ClientParametersAuthentication(apiKey, apiSecret),
apiKey, AUTHORIZATION_SERVER_URL)
.setDataStoreFactory(DATA_STORE_FACTORY)
.setScopes(SCOPE)
.build();
// authorize
LocalServerReceiver receiver =
new LocalServerReceiver.Builder().setHost(DOMAIN).setPort(PORT).build();
Credential credentials = null;
try {
credentials = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
catch (Throwable e) {
e.printStackTrace();
}
return credentials;
}
/**
* Method trying to authorize via an existend refresh-token.
*
* @return Credentials
* @throws IOException
*/
public static Credential authorize(String apiKey, String apiSecret) throws IOException {
Credential reCred = null;
try{
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
StoredCredential cred = (StoredCredential) DATA_STORE_FACTORY.getDataStore("StoredCredential").get(
"user");
try {
TokenResponse response = new RefreshTokenRequest(HTTP_TRANSPORT, JSON_FACTORY, new GenericUrl(TOKEN_SERVER_URL), cred.getRefreshToken()).setClientAuthentication(new ClientParametersAuthentication(apiKey, apiSecret)).setScopes(SCOPE).setGrantType("refresh_token").execute();
credentialDataStore = StoredCredential.getDefaultDataStore(DATA_STORE_FACTORY);
Credential credential = newCredential(apiKey, apiSecret, "user").setFromTokenResponse(response);
if (credentialDataStore != null) {
credentialDataStore.set("user", new StoredCredential(credential));
}
return credential;
}
catch (Exception e) {
e.printStackTrace();
throw new Exception();
}
} catch (Exception e) {
reCred = fullAuthorize(apiKey, apiSecret);
}
return reCred;
}
/**
* Method used to create new Credentials based on a response.
*
* @param userId
* @return Credential
*/
private static Credential newCredential(String apiKey, String apiSecret,String userId) {
try {
Credential reCred = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()).setTransport(HTTP_TRANSPORT).setJsonFactory(JSON_FACTORY).setTokenServerUrl(new GenericUrl(TOKEN_SERVER_URL)).setClientAuthentication(new ClientParametersAuthentication(apiKey, apiSecret)).build();
return reCred;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View file

@ -0,0 +1,81 @@
package moodle.sync.core.fileserver.panopto.util;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
public class XMLWriter {
public static byte[] CreateUpload_manifest(String title, String description, String date, String filename) throws ParserConfigurationException, IOException, SAXException, TransformerException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
// root elements
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("Session");
rootElement.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
rootElement.setAttribute("xmlns:xsd","http://www.w3.org/2001/XMLSchema");
rootElement.setAttribute("xmlns","http://tempuri.org/UniversalCaptureSpecification/v1");
doc.appendChild(rootElement);
Element ti = doc.createElement("Title");
ti.setTextContent(title);
rootElement.appendChild(ti);
Element des = doc.createElement("Description");
des.setTextContent(description);
rootElement.appendChild(des);
Element da = doc.createElement("Date");
da.setTextContent(date);
rootElement.appendChild(da);
Element thumb = doc.createElement("ThumbnailTime");
thumb.setTextContent("PT5S");
rootElement.appendChild(thumb);
Element videos = doc.createElement("Videos");
rootElement.appendChild(videos);
Element video = doc.createElement("Video");
videos.appendChild(video);
Element start = doc.createElement("Start");
start.setTextContent("PT0S");
video.appendChild(start);
Element file = doc.createElement("File");
file.setTextContent(filename);
video.appendChild(file);
Element type = doc.createElement("Type");
type.setTextContent("Primary");
video.appendChild(type);
/*try (FileOutputStream output = new FileOutputStream("C:\\Users\\danie\\OneDrive\\Desktop" +
"\\upload_manifest_generated.xml\\")) {
writeXml(doc, output);
} catch (IOException | TransformerException e) {
e.printStackTrace();
}*/
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
ByteArrayOutputStream bos=new ByteArrayOutputStream();
StreamResult result = new StreamResult(bos);
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
return bos.toByteArray();
}
}

View file

@ -0,0 +1,19 @@
package moodle.sync.core.model.json;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class PanoptoContent {
private String Name;
private String Description;
private String StartTime;
private PanoptoContentUrls Urls;
}

View file

@ -0,0 +1,14 @@
package moodle.sync.core.model.json;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class PanoptoContentUrls {
private String ViewerUrl;
}

View file

@ -0,0 +1,39 @@
package moodle.sync.core.model.json;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import moodle.sync.core.config.MoodleSyncConfiguration;
import java.util.Objects;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PanoptoCourse {
private String Description;
private String ParentFolder;
private PanoptoUrls Urls;
private String Id;
private String Name;
public boolean equals(PanoptoCourse o) {
return Objects.equals(this.Description, o.Description) &&
Objects.equals(this.ParentFolder, o.ParentFolder) &&
Objects.equals(this.Urls, o.Urls) &&
Objects.equals(this.Id, o.Id) &&
Objects.equals(this.Name, o.Name);
}
@Override
public int hashCode() {
return Objects.hash(Description, ParentFolder, Urls, Id, Name);
}
}

View file

@ -0,0 +1,14 @@
package moodle.sync.core.model.json;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class PanoptoFolder {
private String FolderId;
}

View file

@ -0,0 +1,16 @@
package moodle.sync.core.model.json;
import lombok.*;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class PanoptoFolderContent {
private List<PanoptoContent> Results;
}

View file

@ -0,0 +1,18 @@
package moodle.sync.core.model.json;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PanoptoResults {
private List<PanoptoCourse> Results;
}

View file

@ -0,0 +1,15 @@
package moodle.sync.core.model.json;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PanoptoSearchReturn {
private PanoptoResults panoptoResults;
}

View file

@ -0,0 +1,21 @@
package moodle.sync.core.model.json;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class PanoptoSession {
private String ID;
private String UploadTarget;
private String FolderId;
private String SessionId;
}

View file

@ -0,0 +1,22 @@
package moodle.sync.core.model.json;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class PanoptoSessionComplete {
private String ID;
private String UploadTarget;
private String FolderId;
private String State;
private String SessionId;
}

View file

@ -0,0 +1,20 @@
package moodle.sync.core.model.json;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;