Commit de2322f5 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '166-file-management-for-institutes' into 'master'

Resolve "File management for institutes"

Closes #166

See merge request genesys-pgr/genesys-server!87
parents 47a337be 8d47121b
......@@ -7,6 +7,7 @@ services:
- spring.profiles.active=dev
- JAVA_OPTIONS=-Xms1800M -Xmx1800M -server -Dnetworkaddress.cache.ttl=10
- base.host=${CI_ENVIRONMENT_SLUG}.review.genesys-pgr.org
- base.hostname=${CI_ENVIRONMENT_SLUG}.review.genesys-pgr.org
- robots.allow=false
- db.url=jdbc:hsqldb:mem:genesys;sql.syntax_mys=true
- db.driverClassName=org.hsqldb.jdbc.JDBCDriver
......
......@@ -34,6 +34,7 @@ import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.persistence.domain.AccessionRepository;
import org.genesys2.server.service.BatchRESTService;
import org.genesys2.server.service.CropService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.GeoRegionService;
import org.genesys2.server.service.GeoService;
import org.genesys2.server.service.InstituteService;
......@@ -83,6 +84,9 @@ public class FirstRunListener extends RunAsAdminListener {
@Autowired
BatchRESTService batchService;
@Autowired
private GenesysService genesysService;
@Override
protected void init() throws Exception {
if (!createContent) {
......@@ -167,6 +171,7 @@ public class FirstRunListener extends RunAsAdminListener {
LOG.warn("Upserting " + batch.size() + " accession records for " + instCode);
batchService.ensureTaxonomies(institute, batch);
batchService.upsertAccessionData(institute, batch);
genesysService.updateAccessionCount(institute);
}
} catch (JsonParseException e) {
......
......@@ -151,7 +151,7 @@ public interface GenesysService {
List<Accession> saveAccessions(Iterable<Accession> accession);
void updateAccessionCount(FaoInstitute institute);
FaoInstitute updateAccessionCount(FaoInstitute institute);
List<SvalbardDeposit> getSvalbardData(AccessionId accession);
......
/**
* Copyright 2014 Global Crop Diversity Trust
/*
* Copyright 2017 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,7 +12,7 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
*/
package org.genesys2.server.service.impl;
......@@ -248,12 +248,12 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
return accessionRepository.countByHistoric(true);
}
@Override
public long countByCrop(final Crop crop) {
return accessionRepository.countByCrop(crop);
}
@Override
public long countByCrop(final Crop crop) {
return accessionRepository.countByCrop(crop);
}
@Override
@Override
public long countByInstitute(FaoInstitute institute) {
return accessionRepository.countByInstitute(institute);
}
......@@ -401,7 +401,8 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
if (all.accession.getCrop() != null) {
ad.crops(all.accession.getCrop().getShortName());
} else {
// Ignore taxonomy crops: ad.crops(cropService.getCrops(all.accession.getTaxonomy()));
// Ignore taxonomy crops:
// ad.crops(cropService.getCrops(all.accession.getTaxonomy()));
}
return ad;
}
......@@ -755,14 +756,15 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
}
@Override
@Transactional(readOnly = false)
@Transactional
// @CacheEvict(value = "statistics", allEntries = true)
public void updateAccessionCount(FaoInstitute institute) {
public FaoInstitute updateAccessionCount(FaoInstitute institute) {
if (institute == null)
return;
return institute;
long accessionCount = accessionRepository.countByInstitute(institute);
institute = instituteRepository.getOne(institute.getId());
institute.setAccessionCount(accessionCount);
instituteRepository.save(institute);
return instituteRepository.save(institute);
}
/**
......@@ -811,7 +813,8 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
public List<Accession> saveAccessions(Iterable<Accession> accessions) {
Set<FaoInstitute> institutes = new HashSet<FaoInstitute>();
for (Accession accession : accessions) {
// System.out.println("Saving " + accession + " STO=" + accession.getStoRage() + " ST=" +
// System.out.println("Saving " + accession + " STO=" + accession.getStoRage() +
// " ST=" +
// accession.getStorage());
institutes.add(accession.getInstitute());
}
......@@ -863,10 +866,12 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
}
/**
* Update {@link SvalbardDeposit} data and link with Genesys accessions. The primary key for {@link SvalbardDeposit} is the <code>sgsv_id</code> as provided by
* NordGen.
* Update {@link SvalbardDeposit} data and link with Genesys accessions. The
* primary key for {@link SvalbardDeposit} is the <code>sgsv_id</code> as
* provided by NordGen.
*
* Any existing SGSV records are first deleted. Inserted and linked with accessions in this method.
* Any existing SGSV records are first deleted. Inserted and linked with
* accessions in this method.
*
* @param svalbardDeposits
* @return
......@@ -897,7 +902,8 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
LOG.debug("Linked " + updatedCount + " accessions by alias in set " + sgsvIds);
}
// link indirectly where INSTCODE matches alternative sgsvCode, GENUS and ACCENUMB match
// link indirectly where INSTCODE matches alternative sgsvCode, GENUS and
// ACCENUMB match
updatedCount = svalbardRepository.linkInDirectly(sgsvIds);
if (updatedCount > 0 && LOG.isDebugEnabled()) {
LOG.debug("Linked " + updatedCount + " accessions using alternate code in set " + sgsvIds);
......
......@@ -21,13 +21,24 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.genesys.filerepository.InvalidRepositoryFileDataException;
import org.genesys.filerepository.InvalidRepositoryPathException;
import org.genesys.filerepository.NoSuchRepositoryFileException;
import org.genesys.filerepository.model.ImageGallery;
import org.genesys.filerepository.model.RepositoryFile;
import org.genesys.filerepository.service.ImageGalleryService;
import org.genesys.filerepository.service.RepositoryService;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.service.CRMException;
......@@ -47,6 +58,7 @@ import org.genesys2.server.service.impl.FilterHandler.AppliedFilters;
import org.genesys2.server.service.impl.SearchException;
import org.genesys2.spring.ResourceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
......@@ -55,17 +67,28 @@ import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.util.UriUtils;
@Controller
@Scope("request")
@RequestMapping("/wiews")
public class WiewsController extends BaseController {
private static final String MANAGE_FILES_JSP_PATH = "/wiews/files";
@Autowired
private InstituteService instituteService;
......@@ -93,6 +116,12 @@ public class WiewsController extends BaseController {
@Autowired
private ElasticService elasticService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private ImageGalleryService imageGalleryService;
@RequestMapping("/")
public String view(ModelMap model, @RequestParam(value = "page", required = false, defaultValue = "1") int page) {
model.addAttribute("pagedData", instituteService.listPGRInstitutes(new PageRequest(page - 1, 50, new Sort("code"))));
......@@ -432,4 +461,178 @@ public class WiewsController extends BaseController {
_logger.warn("Download was aborted", e);
}
}
/* File management */
@PreAuthorize("hasRole('ADMINISTRATOR')")
@RequestMapping(value = "/{wiewsCode}/files/**", method = RequestMethod.GET)
public String listAllFiles(HttpServletRequest request, ModelMap model) throws UnsupportedEncodingException, InvalidRepositoryPathException {
String fullpath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
// The /** mapping does not decode the URL
fullpath = UriUtils.decode(fullpath, "UTF-8");
return listAllFiles(model, fullpath);
}
@PreAuthorize("hasRole('ADMINISTRATOR')")
@RequestMapping(value = "/{path}/files", method = RequestMethod.GET)
public String listAllFiles(ModelMap model, @PathVariable(value = "path") String path) throws InvalidRepositoryPathException {
final String repositoryPath = path.contains("/wiews/") ? path.replace("/files/", "/") : "/wiews/" + path;
if (_logger.isDebugEnabled()) {
_logger.debug("Listing files for path=" + repositoryPath);
}
String wiewsCode = path.replace("/wiews/", "");
wiewsCode = wiewsCode.contains("/") ? wiewsCode.substring(0, wiewsCode.indexOf("/")) : wiewsCode;
List<String> subPaths = new ArrayList<>();
for (String subPath: repositoryService.listPaths(repositoryPath, new PageRequest(0, 10))) {
if (!subPath.equals(repositoryPath) && subPath.contains(repositoryPath)) {
subPaths.add(subPath.substring(repositoryPath.length()));
}
}
model.addAttribute("fileList", repositoryService.getFiles(repositoryPath));
model.addAttribute("currentPath", repositoryPath);
model.addAttribute("subPaths", subPaths);
model.addAttribute("imageGallery", imageGalleryService.loadImageGallery(repositoryPath));
model.addAttribute("wiewsCode", wiewsCode);
return MANAGE_FILES_JSP_PATH + "/index";
}
@PreAuthorize("hasRole('ADMINISTRATOR')")
@RequestMapping(value = "/upload-file", method = RequestMethod.POST)
public String uploadFile(@RequestParam MultipartFile file, @RequestParam String wiewsCode, @RequestParam String repositoryPath,
RedirectAttributes redirectAttributes) throws IOException {
final String mimeType = file.getContentType();
try {
if (mimeType.startsWith("image")) {
repositoryService.addImage(repositoryPath, file.getOriginalFilename(), file.getContentType(), file.getBytes(), null);
} else {
repositoryService.addFile(repositoryPath, file.getOriginalFilename(), file.getContentType(), file.getBytes(), null);
}
} catch (InvalidRepositoryPathException e) {
_logger.error("Invalid repository path!", e);
redirectAttributes.addFlashAttribute("errorMessage", "Invalid repository path!");
} catch (InvalidRepositoryFileDataException e) {
_logger.error("Invalid file data!", e);
redirectAttributes.addFlashAttribute("errorMessage", "Invalid file data!");
}
if (repositoryPath.equals("/wiews/".concat(wiewsCode))) {
return "redirect:" + repositoryPath + "/files";
} else {
return "redirect:" + repositoryPath.replace("/wiews/".concat(wiewsCode).concat("/"), "/wiews/".concat(wiewsCode).concat("/files/"));
}
}
@PreAuthorize("hasRole('ADMINISTRATOR')")
@RequestMapping(value = "/delete-file", method = RequestMethod.POST)
public String deleteFile(@RequestParam String uuid, @RequestParam String wiewsCode) throws NoSuchRepositoryFileException, IOException {
RepositoryFile repositoryFile = repositoryService.getFile(UUID.fromString(uuid));
repositoryService.removeFile(repositoryFile);
if (repositoryFile.getPath().equals("/wiews/".concat(wiewsCode))) {
return "redirect:" + repositoryFile.getPath() + "/files";
} else {
return "redirect:" + repositoryFile.getPath().replace("/wiews/".concat(wiewsCode).concat("/"), "/wiews/".concat(wiewsCode).concat("/files/"));
}
}
@PreAuthorize("hasRole('ADMINISTRATOR')")
@RequestMapping(value = "/{wiewsCode}/edit-file", method = RequestMethod.GET)
public String getEditPage(@RequestParam String uuid, @PathVariable(value = "wiewsCode") String wiewsCode, ModelMap model) throws NoSuchRepositoryFileException {
RepositoryFile file = repositoryService.getFile(UUID.fromString(uuid));
model.addAttribute("file", file);
model.addAttribute("wiewsCode", wiewsCode);
return MANAGE_FILES_JSP_PATH + "/edit";
}
@PreAuthorize("hasRole('ADMINISTRATOR')")
@RequestMapping(value = "/{wiewsCode}/update-file", method = RequestMethod.POST)
public String updateMetadata(@ModelAttribute RepositoryFile fileData, @RequestParam String uuid, @PathVariable(value = "wiewsCode") String wiewsCode) throws NoSuchRepositoryFileException {
RepositoryFile updatedFile = repositoryService.getFile(UUID.fromString(uuid));
repositoryService.updateMetadata(updatedFile.getUuid(), fileData);
return "redirect:/wiews/" + wiewsCode + "/files";
}
@GetMapping(value = "/{wiewsCode}/files/gallery")
public String listAllFiles(ModelMap model, @PathVariable("wiewsCode") String wiewsCode, HttpServletRequest request) {
return "redirect:/wiews/" + wiewsCode + "/files" + "/gallery" + "/1";
}
@GetMapping(value = "/{wiewsCode}/files/gallery/{page:\\d+}")
public String listAllFiles(ModelMap model, @PathVariable("page") int page, @PathVariable("wiewsCode") String wiewsCode) {
Page<ImageGallery> pagedData = imageGalleryService.listImageGalleries(new PageRequest(page - 1, 50, new Sort("path")));
model.addAttribute("pagedData", pagedData);
model.addAttribute("wiewsCode", wiewsCode);
return MANAGE_FILES_JSP_PATH + "/gallery/index";
}
@GetMapping(value = "/{wiewsCode}/files/gallery/details")
public String listAllFiles(ModelMap model, HttpServletRequest request, @PathVariable("wiewsCode") String wiewsCode) {
ImageGallery imageGallery = imageGalleryService.loadImageGallery("/wiews/" + wiewsCode);
if (imageGallery == null) {
throw new ResourceNotFoundException("No image gallery here!");
}
imageGalleryService.ensureThumbnails(imageGallery, 200, 200);
model.addAttribute("thumbnailFormat", "200x200");
model.addAttribute("imageGallery", imageGallery);
model.addAttribute("wiewsCode", wiewsCode);
return MANAGE_FILES_JSP_PATH + "/gallery/details";
}
@GetMapping(value = "/{path}/files/gallery/edit")
public String getEditPage(@RequestParam String galleryPath, ModelMap model) throws NoSuchRepositoryFileException {
ImageGallery imageGallery = imageGalleryService.loadImageGallery(galleryPath);
if (imageGallery == null) {
imageGallery = new ImageGallery();
imageGallery.setPath(galleryPath);
}
model.addAttribute("imageGallery", imageGallery);
model.addAttribute("wiewsCode", galleryPath);
return MANAGE_FILES_JSP_PATH + "/gallery/edit";
}
@PostMapping(value = "{wiewsCode}/files/gallery/update")
public String updateMetadata(@PathVariable("wiewsCode") String wiewsCode, @ModelAttribute ImageGallery imageGallery, RedirectAttributes redirectAttributes) throws NoSuchRepositoryFileException {
ImageGallery updatedGallery = imageGalleryService.loadImageGallery(imageGallery.getPath());
if (updatedGallery == null) {
updatedGallery = imageGalleryService.createImageGallery(imageGallery.getPath(), imageGallery.getTitle(), imageGallery.getDescription());
} else {
updatedGallery = imageGalleryService.updateImageGalery(updatedGallery, imageGallery.getTitle(), imageGallery.getDescription());
}
redirectAttributes.addFlashAttribute("successMessage", "repository.gallery.successfully-updated");
return "redirect:/wiews/" + wiewsCode +"/files/gallery";
}
@PostMapping(value = "{wiewsCode}/files/gallery/delete")
public String deleteFile(@RequestParam String galleryPath, RedirectAttributes redirectAttributes, @PathVariable("wiewsCode") String wiewsCode) throws InvalidRepositoryPathException {
ImageGallery imageGallery = imageGalleryService.loadImageGallery(galleryPath);
imageGalleryService.removeGallery(imageGallery);
redirectAttributes.addFlashAttribute("successMessage", "repository.gallery.removed");
return "redirect:/wiews/" + wiewsCode +"/files/gallery";
}
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
}
......@@ -867,6 +867,7 @@ repository.file.lastModifiedDate=Last modified date
file.upload-file=Upload file
file.upload-file.help=Select file for upload from local computer
file.manage-files=Manage files
repository.gallery=Image gallery
repository.gallery.title=Title of image gallery:
......
[{
"instCode": "PER001",
"doi": "10.0155/43X~",
"acceNumb": "CIP 102081.28",
"genus": "Solanum",
"cropName": "Sweetpotato",
......
......@@ -6532,3 +6532,10 @@ table.accessions {
font-family: "Roboto-Bold";
font-size: 30px;
}
.margin-top-05 { margin-top: 5px; }
.margin-top-10 { margin-top: 10px; }
.margin-top-15 { margin-top: 15px; }
.margin-top-20 { margin-top: 20px; }
.margin-top-25 { margin-top: 25px; }
.margin-top-30 { margin-top: 30px; }
......@@ -382,9 +382,21 @@
<!-- End: basic info section -->
<!-- Image gallery section -->
<security:authorize access="hasRole('ADMINISTRATOR') or hasPermission(#accession.institute, 'ADMINISTRATION')">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 form-group">
<a href="<c:url value="/wiews/${accession.institute.code}/files/acn/${accession.accessionName}" />" class="btn btn-default">
<spring:message code="file.manage-files" />
</a>
</div>
</div>
</security:authorize>
<c:if test="${imageGallery ne null}">
<div class="collect-info gallery">
<h4 class="row section-heading"><spring:message code="accession.imageGallery" /></h4>
<h4 class="row section-heading">
<spring:message code="accession.imageGallery" />
</h4>
<div class="section-inner-content clearfix">
<div class="row imagegallery thumbs" id="accession-images-thumbs">
<c:forEach items="${imageGallery.images}" var="image">
......
......@@ -494,13 +494,16 @@
</c:if>
<security:authorize access="hasRole('ADMINISTRATOR') or hasPermission(#faoInstitute, 'ADMINISTRATION')">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<a href="<c:url value="/acl/${faoInstitute.getClass().name}/${faoInstitute.id}/permissions"><c:param name="back">/wiews/${faoInstitute.code}</c:param></c:url>" class="close">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 form-group">
<a href="<c:url value="/acl/${faoInstitute.getClass().name}/${faoInstitute.id}/permissions"><c:param name="back">/wiews/${faoInstitute.code}</c:param></c:url>" class="btn btn-default">
<spring:message code="edit-acl" />
</a>
<a href="<c:url value="/wiews/${faoInstitute.code}/edit" />" class="close">
<a href="<c:url value="/wiews/${faoInstitute.code}/edit" />" class="btn btn-default">
<spring:message code="edit" />
</a>
<a href="<c:url value="/wiews/${faoInstitute.code}/files" />" class="btn btn-default">
<spring:message code="file.manage-files" />
</a>
</div>
</security:authorize>
......
<!DOCTYPE html>
<%@ include file="/WEB-INF/jsp/init.jsp" %>
<html>
<head>
<title><spring:message code="admin.page.title"/></title>
</head>
<body>
<h4>Updating metadata for file <strong><c:out value="${file.originalFilename}"/></strong></h4>
<a href="<c:url value="/wiews/${wiewsCode}/files" />" class="btn btn-default margin-top-10">
<spring:message code="cancel"/>
</a>
<form action="<c:url value="/wiews/${wiewsCode}/update-file" />" method="post">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="hidden" name="uuid" value="${file.uuid}"/>
<input type="hidden" name="md5Sum" value="${file.md5Sum}"/>
<input type="hidden" name="sha1Sum" value="${file.sha1Sum}"/>
<input type="hidden" name="path" value="${file.path}"/>
<div class="row">
<div class="col-md-6 margin-top-20">
<label for="title"><spring:message code="repository.file.title"/></label>
<input type="text" class="form-control" id="title" name="title" value="${file.title}"
placeholder="<spring:message code="repository.file.title" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="subject"><spring:message code="repository.file.subject"/></label>
<input type="text" class="form-control" id="subject" name="subject" value="${file.subject}"
placeholder="<spring:message code="repository.file.subject" />">
</div>
<div class="col-md-12 margin-top-20">
<label for="description"><spring:message code="repository.file.description"/></label>
<textarea id="description" name="description" class="form-control"><c:out escapeXml="false"
value="${file.description}"/></textarea>
</div>
<div class="col-md-6 margin-top-20">
<label for="creator"><spring:message code="repository.file.creator"/></label>
<input type="text" id="creator" name="creator" class="form-control" value="${file.creator}"
placeholder="<spring:message code="repository.file.creator" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="created"><spring:message code="repository.file.created"/></label>
<input type="text" id="created" name="created" class="form-control" value="${file.created}"
placeholder="<spring:message code="repository.file.created" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="rightsHolder"><spring:message code="repository.file.rightsHolder"/></label>
<input type="text" id="rightsHolder" name="rightsHolder" class="form-control" value="${file.rightsHolder}"
placeholder="<spring:message code="repository.file.rightsHolder" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="accessRights"><spring:message code="repository.file.accessRights"/></label>
<input type="text" id="accessRights" name="accessRights" class="form-control" value="${file.accessRights}"
placeholder="<spring:message code="repository.file.accessRights" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="license"><spring:message code="repository.file.license"/></label>
<input type="text" id="license" name="license" class="form-control" value="${file.license}"
placeholder="<spring:message code="repository.file.license" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="originalFilename"><spring:message code="repository.file.originalFilename"/></label>
<input type="text" id="originalFilename" name="originalFilename" class="form-control"
value="${file.originalFilename}"
placeholder="<spring:message code="repository.file.originalFilename" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="contentType"><spring:message code="repository.file.contentType"/></label>
<input type="text" id="contentType" name="contentType" class="form-control" value="${file.contentType}"
placeholder="<spring:message code="repository.file.contentType" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="extent"><spring:message code="repository.file.extent"/></label>
<input type="text" id="extent" name="extent" class="form-control" value="${file.extent}"
placeholder="<spring:message code="repository.file.extent" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="bibliographicCitation"><spring:message code="repository.file.bibliographicCitation"/></label>
<input type="text" id="bibliographicCitation" name="bibliographicCitation" class="form-control"
value="${file.bibliographicCitation}"
placeholder="<spring:message code="repository.file.bibliographicCitation" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="dateSubmitted"><spring:message code="repository.file.dateSubmitted"/></label>
<input type="text" id="dateSubmitted" name="createdDate" class="form-control" value="${file.dateSubmitted}"
placeholder="<spring:message code="repository.file.dateSubmitted" />">
</div>
<div class="col-md-6 margin-top-20">
<label for="modified"><spring:message code="repository.file.lastModifiedDate"/></label>