Skip to content

Commit

Permalink
SAK-46629 dashboards. Add dashboards to site import
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianfish committed Mar 4, 2024
1 parent 9e82c4d commit 7b208a6
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
import org.sakaiproject.webapi.formatter.EpochMillisFormatter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
Expand All @@ -28,19 +26,6 @@
@ComponentScan("org.sakaiproject.webapi")
public class WebMvcConfiguration implements WebMvcConfigurer {

@Override
public void configureAsyncSupport (AsyncSupportConfigurer configurer) {

ThreadPoolTaskExecutor t = new ThreadPoolTaskExecutor();
t.setCorePoolSize(10);
t.setMaxPoolSize(100);
t.setQueueCapacity(50);
t.setAllowCoreThreadTimeOut(true);
t.setKeepAliveSeconds(120);
t.initialize();
configurer.setTaskExecutor(t);
}

@Override
public void addFormatters(FormatterRegistry registry) {
EpochMillisFormatter formatter = new EpochMillisFormatter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.content.api.ContentHostingService;
import org.sakaiproject.content.api.ContentResource;
import org.sakaiproject.content.api.ContentResourceEdit;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.EntityProducer;
import org.sakaiproject.entity.api.EntityTransferrer;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.event.api.NotificationService;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.PermissionException;
Expand Down Expand Up @@ -57,25 +63,32 @@
import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import lombok.extern.slf4j.Slf4j;

/**
*/
@Slf4j
@RestController
public class DashboardController extends AbstractSakaiApiController {
public class DashboardController extends AbstractSakaiApiController implements EntityProducer, EntityTransferrer {

private static final String DASHBOARD_TOOL_ID = "sakai.dashboard";
private static final String REFERENCE_ROOT = Entity.SEPARATOR + "dashboard";

@Resource
private AnnouncementService announcementService;

@Resource
private ContentHostingService contentHostingService;

@Resource
private EntityManager entityManager;

@Resource
private SecurityService securityService;

Expand Down Expand Up @@ -143,6 +156,8 @@ public void init() {
defaultWidgetLayouts.put("3", courseWidgetLayout3);

maxNumberMotd = serverConfigurationService.getInt("dashboard.home.motd.display", 1);

entityManager.registerEntityProducer(this, REFERENCE_ROOT);
}

@GetMapping(value = "/users/{userId}/dashboard", produces = MediaType.APPLICATION_JSON_VALUE)
Expand Down Expand Up @@ -345,8 +360,112 @@ public String saveSiteImage(HttpServletRequest req, @PathVariable String siteId)
siteService.save(site);
return edit.getUrl();
} catch (Exception e) {
log.error("Failed to update image for site {}", siteId, e);
log.error("Failed to update image for site {}: {}", siteId, e.toString());
throw e;
}
}
}

@Override
public String getLabel() {
return "dashboard";
}

@Override
public boolean parseEntityReference(String reference, Reference ref) {

if (!reference.startsWith(REFERENCE_ROOT)) {
return false;
}

return true;
}

@Override
public Optional<String> getTool() {
return Optional.of(DASHBOARD_TOOL_ID);
}

@Override
public String[] myToolIds() {
return new String[] { DASHBOARD_TOOL_ID };
}

@Override
public Map<String, String> transferCopyEntities(String fromContext, String toContext, List<String> ids, List<String> options) {

try {
Site fromSite = siteService.getSite(fromContext);
String fromConfig = fromSite.getProperties().getProperty("dashboard-config");
if (fromConfig != null) {
Site toSite = siteService.getSite(toContext);
toSite.getProperties().addProperty("dashboard-config", fromConfig);
siteService.save(toSite);
}
} catch (IdUnusedException idue) {
log.error("No site found for {} or {}", fromContext, toContext);
} catch (Exception e) {
log.error("Failed to copy the dashboard config: {}", e.toString());
}

Map<String, String> map = Collections.EMPTY_MAP;

String fromCollectionId = contentHostingService.getSiteCollection(fromContext);

if (fromCollectionId == null) return map;

try {
contentHostingService.checkCollection(fromCollectionId);
} catch (Exception e) {
log.warn("No access to site {}'s content collection", fromContext);
return map;
}

String toCollectionId = contentHostingService.getSiteCollection(toContext);

try {
contentHostingService.checkCollection(toCollectionId);
} catch (Exception e) {
try {
contentHostingService.commitCollection(contentHostingService.addCollection(toCollectionId));
} catch (Exception e2) {
log.error("Failed to add collection {}: {}", toCollectionId, e2.toString());
}
}

String sourceId = fromCollectionId + "course_image.png";

try {
contentHostingService.getResource(sourceId);
} catch (Exception e) {
// This is okay. No course image in the source site, not a problem.
return map;
}

String targetId = toCollectionId + "course_image.png";

// Attempt to remove the current course image
try {
contentHostingService.removeResource(targetId);
} catch (Exception e) {
// This is okay. Maybe there wasn't a course image.
}

try {
String newId = contentHostingService.copy(sourceId, targetId);
ContentResource newResource = contentHostingService.getResource(newId);
Site toSite = siteService.getSite(toContext);
toSite.getProperties().addProperty(Site.PROP_COURSE_IMAGE_URL, newResource.getUrl());
siteService.save(toSite);
} catch (Exception e) {
log.error("Failed to copy dashboard image resource: {}", e.toString());
}

return map;
}

@Override
public Map<String, String> transferCopyEntities(String fromContext, String toContext, List<String> ids, List<String> options, boolean cleanup) {

return transferCopyEntities(fromContext, toContext, ids, options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export class SakaiCourseDashboard extends SakaiElement {

this.data.image = e.detail.url;
this.newImageBlob = e.detail.blob;
this.querySelector("sakai-course-header").requestUpdate();
this.requestUpdate();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class SakaiImageEditor extends SakaiDialogContent {
content() {

return html`
<input type="file" accept="image/*" value="Choose an image" @change=${this.filePicked} />
<input type="file" accept="image/*" @change=${this.filePicked} />
<img id="image" src="${this.imageUrl}" width="200" />
<div id="controls">
<sakai-button @click=${this.zoomIn} type="small" title="${this._i18n.zoom_in}" arial-label="${this._i18n.zoom_in}">
Expand Down Expand Up @@ -118,6 +118,9 @@ export class SakaiImageEditor extends SakaiDialogContent {
SakaiDialogContent.styles,
cropperStyles,
css`
input[type='file'] {
margin-bottom: 10px;
}
#controls {
margin-top: 10px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ export class SakaiPictureChanger extends SakaiElement {
postBody.append("base64", base64);

const url = "/direct/profile-image/upload";

console.log(url);
fetch(url, {
credentials: "include",
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
Expand All @@ -168,6 +170,8 @@ export class SakaiPictureChanger extends SakaiElement {
})
.then(data => {

console.log(data);

if (data.status == "SUCCESS") {
this._uploadError = false;
this._needsSave = false;
Expand Down

0 comments on commit 7b208a6

Please sign in to comment.