Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 83 additions & 44 deletions src/main/scala/org/aphreet/c3/lib/FileUpload.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import org.aphreet.c3.lib.DependencyFactory._
import com.ifunsoftware.c3.access.{C3AccessException, DataStream, C3System}
import com.ifunsoftware.c3.access.C3System._
import org.aphreet.c3.lib.metadata.Metadata._
import org.aphreet.c3.util.C3Loggable
import org.aphreet.c3.util.{C3Exception, C3Loggable}
import org.aphreet.c3.model.{Group, User}
import net.liftweb.util.Helpers
import Helpers._
Expand All @@ -51,59 +51,75 @@ import org.aphreet.c3.service.journal.EventType
import org.aphreet.c3.util.helpers.FileTransferHelper

// for ajax file upload
object FileUpload extends RestHelper with C3Loggable{
object FileUpload extends RestHelper with C3Loggable {
val c3 = inject[C3System].openOrThrowException("Cannot wire a C3 System")

private val RegexGroupId = """.*groups/([^/]*)/.*""".r
private val isCallbackEnabled = false

serve {
case "upload" :: "file" :: currentPath Post req => {
withCurrentUserAndGroupCtx(req, currentPath){
withCurrentUserAndGroupCtx(req, currentPath) {

val uploads = req.uploadedFiles
logger.info("Uploaded files: " + uploads)
val uploads = req.uploadedFiles
logger.info("Uploaded files: " + uploads)

val filePath = c3FilePath(currentPath)
val filePath = c3FilePath(currentPath)

logger.info("Path to upload: " + filePath)
userGroupIds: UserGroupIds => {
logger.info("Path to upload: " + filePath)
userGroupIds: UserGroupIds => {

try{
try {
val ojv: List[JObject] = uploads.map { fph =>
val url = removeTrailingIndex(currentPath).mkString("/", "/", "/") + fph.fileName
val description = req.param(s"description_${fph.fileName}") match {case Full(temp) => temp; case _ => ""}
val description = req.param(s"description_${fph.fileName}") match {
case Full(temp) => temp;
case _ => ""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is necessary field for filling, in this case we should throw warning msg.

}

val tags = req.param(s"tags_${fph.fileName}") match {
case Full(temp) => temp;
case _ => ""
}

if (description == "") { throw new IllegalArgumentException("Description is empty") }
if (tags == "") { throw new Exception("Tags are empty") }

val tags = req.param(s"tags_${fph.fileName}") match {case Full(temp) => temp; case _ => ""}
val fileMetadata: Map[String, String] =
Map((OWNER_ID_META -> userGroupIds.userId), (GROUP_ID_META -> userGroupIds.groupId),(DESCRIPTION_META -> description),(TAGS_META -> tags))
//req param("metadata") map(s => Map((TAGS_META -> s))) openOr Map()
Map((OWNER_ID_META -> userGroupIds.userId), (GROUP_ID_META -> userGroupIds.groupId), (DESCRIPTION_META -> description), (TAGS_META -> tags))
//req param("metadata") map(s => Map((TAGS_META -> s))) openOr Map()
uploadToC3(fph, filePath, fileMetadata)
("name" -> fph.fileName) ~
("url" -> url) ~
("sizef" -> fph.length) ~
("delete_url" -> ("/delete/file" + url)) ~
("delete_type" -> "DELETE")
}

uploadToC3(fph, filePath, fileMetadata)
("name" -> fph.fileName) ~
("url" -> url) ~
("sizef" -> fph.length) ~
("delete_url" -> ("/delete/file" + url)) ~
("delete_type" -> "DELETE")
}
val jr = JsonResponse(ojv).toResponse.asInstanceOf[InMemoryResponse]
InMemoryResponse(jr.data, ("Content-Length", jr.data.length.toString) ::
("Content-Type", "text/plain") :: S.getHeaders(Nil),
S.responseCookies, 200)

val jr = JsonResponse(ojv).toResponse.asInstanceOf[InMemoryResponse]
InMemoryResponse(jr.data, ("Content-Length", jr.data.length.toString) ::
("Content-Type", "text/plain") :: S.getHeaders(Nil),
S.responseCookies, 200)
} catch {
case e: C3AccessException => {
if (e.message.endsWith("already exists")) // that's ugly, need a proper cause from access api
errorResponse(uploads, 409, "File already exists")
else
BadResponse()
}
case e: IllegalArgumentException => {
if (e.getMessage().endsWith("empty"))
errorResponse(uploads, 404, e.getMessage())
else
BadResponse()
}
}
}
}
}
case "replace" :: "file" :: currentPath Post req => {
withCurrentUserAndGroupCtx(req, currentPath){
withCurrentUserAndGroupCtx(req, currentPath) {
userGroupIds: UserGroupIds => {

val uploads = req.uploadedFiles
Expand All @@ -114,24 +130,25 @@ object FileUpload extends RestHelper with C3Loggable{

val oldFile = c3.getFile(oldFilePath.mkString("/", "/", ""))
logger.info("Path to upload: " + filePath)
try{
val ojv: List[JObject] = uploads.map { fph =>
val url = removeTrailingIndex(currentPath).mkString("/", "/", "/") + fph.fileName
val fileMetadata: Map[String, String] =
Map((OWNER_ID_META -> userGroupIds.userId), (GROUP_ID_META -> userGroupIds.groupId),(DESCRIPTION_META -> oldFile.metadata.get(DESCRIPTION_META).getOrElse("")),
(TAGS_META -> oldFile.metadata.get(TAGS_META).getOrElse("")))
val group: Box[Group] = Group.findById(filePath.head)
val relativeFilePathString = filePath.drop(2) mkString "/"
FileTransferHelper.moveToTrashCan(oldFile.name, group.open_!, "/"+relativeFilePathString, true)
uploadToC3(fph, filePath.dropRight(1), fileMetadata)
("name" -> fph.fileName) ~
("url" -> url) ~
("sizef" -> fph.length) ~
("delete_url" -> ("/delete/file" + url)) ~
("delete_type" -> "DELETE")
}
try {
val ojv: List[JObject] = uploads.map { fph =>
val url = removeTrailingIndex(currentPath).mkString("/", "/", "/") + fph.fileName
val fileMetadata: Map[String, String] =
Map((OWNER_ID_META -> userGroupIds.userId), (GROUP_ID_META -> userGroupIds.groupId), (DESCRIPTION_META -> oldFile.metadata.get(DESCRIPTION_META).getOrElse("")),
(TAGS_META -> oldFile.metadata.get(TAGS_META).getOrElse("")))
val group = Group.findById(filePath.head).open_!
val relativeFilePathString = filePath.drop(2) mkString "/"
if (group.getFile(group.trashCanDirectory).openOr(null) == null) createTrashCan(group);
FileTransferHelper.moveToTrashCan(oldFile.name, group, "/" + relativeFilePathString, true)
uploadToC3(fph, filePath.dropRight(1), fileMetadata)
("name" -> fph.fileName) ~
("url" -> url) ~
("sizef" -> fph.length) ~
("delete_url" -> ("/delete/file" + url)) ~
("delete_type" -> "DELETE")
}

val jr = JsonResponse(ojv).toResponse.asInstanceOf[InMemoryResponse]
val jr = JsonResponse(ojv).toResponse.asInstanceOf[InMemoryResponse]
InMemoryResponse(jr.data, ("Content-Length", jr.data.length.toString) ::
("Content-Type", "text/plain") :: S.getHeaders(Nil),
S.responseCookies, 200)
Expand All @@ -143,11 +160,11 @@ object FileUpload extends RestHelper with C3Loggable{
BadResponse()
}
}
}
}
}
}
case "delete" :: "file" :: currentPath Delete req => {
withCurrentUserAndGroupCtx(req, currentPath){
withCurrentUserAndGroupCtx(req, currentPath) {
userGroupIds: UserGroupIds => {
val filePath = c3FilePath(currentPath)
logger.info("File to be deleted: " + removeTrailingIndex(currentPath).mkString("/", "/", ""))
Expand All @@ -161,6 +178,28 @@ object FileUpload extends RestHelper with C3Loggable{

case class UserGroupIds(userId: String, groupId: String)

private def createTrashCan(group: Group): Unit = {
val root = c3.getFile("/").asDirectory
root.getChild(group.getId) match {
case Some(node) =>
val dir = node.asDirectory
dir.getChild("files") match {
case Some(node) =>
val files = node.asDirectory
val metadata = Map(OWNER_ID_META -> dir.metadata.get(OWNER_ID_META).getOrElse(User.id.is.toString),
GROUP_ID_META -> group.getId,
TAGS_META -> "Trash",
DESCRIPTION_META -> "",
ACL_META -> dir.metadata.get(ACL_META).getOrElse(""))
files.createDirectory(group.trashCanName, metadata)
case None => throw new C3Exception("Failed to create trash can for group " + group.getId)
}
case None => throw new C3Exception("Can't find group with id " + group.getId)
}
}



private def withCurrentUserAndGroupCtx(req: Req, currentPath: List[String])(block: UserGroupIds => LiftResponse): LiftResponse = {
val currentUser = User.currentUser
val groupIdOpt = extractGroupId(currentPath)
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/org/aphreet/c3/lib/metadata/Metadata.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ object Metadata {
val DESCRIPTION_META = "x-c3-description"
val CONTENT_TYPE = "content-type"
val ACL_META = "x-c3-acl"
val ORIGINAL_NAME_META = "x-c3-original-name"
val TAGS_META: String = "x-c3-tags"
val MSG_CREATOR_META: String = "x-c3-msg-creator"
val MSG_DATE_META: String = "x-c3-msg-date"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ class GroupPageFiles(data: GroupPageFilesData) extends C3ResourceHelpers
JsCmds.SetHtml("right-box-head", <span>
{ file.name }
</span>) &
JsCmds.SetHtml("description", <span>
{ ConvertHelper.ShortString(file.metadata.get(DESCRIPTION_META).getOrElse("")) }
</span>) &
JsCmds.SetHtml("description_box", <span>
{ ConvertHelper.ShortString(file.metadata.get(DESCRIPTION_META).getOrElse("")) }
</span>) &
JsCmds.SetHtml("edit_tags_form", <span>
{ file.metadata.get(TAGS_META).map(_.split(",").mkString(", ")).getOrElse("") }
</span>) &
Expand Down Expand Up @@ -742,9 +742,11 @@ class GroupPageFiles(data: GroupPageFilesData) extends C3ResourceHelpers
GROUP_ID_META -> data.group.getId,
TAGS_META -> tags.trim,
DESCRIPTION_META -> description.trim,
ACL_META -> currentDirectory.metadata.get(ACL_META).getOrElse(""))
currentDirectory.createDirectory(name.trim, metadata)
journalServer.foreach(_ ! JournalServerEvent(User.currentUserUnsafe, group, EventType.CreateResources, currentDirectory.fullname + name.trim))
ACL_META -> currentDirectory.metadata.get(ACL_META).getOrElse(""),
ORIGINAL_NAME_META -> name)
val normalizedName = normilizeFileName(name)
currentDirectory.createDirectory(normalizedName.trim, metadata)
journalServer.foreach(_ ! JournalServerEvent(User.currentUserUnsafe, group, EventType.CreateResources, currentDirectory.fullname + normalizedName.trim))
S.redirectTo(currentPath) // redirect on the same page
}
}
Expand All @@ -755,6 +757,10 @@ class GroupPageFiles(data: GroupPageFilesData) extends C3ResourceHelpers
"type=submit" #> SHtml.onSubmitUnit(createDirectory)
}

private def normilizeFileName(name: String): String = {
name.replace(':', '-').replace('/', '-').replace('\\', '-')
}

private def combineUserMetadata(metadata: scala.collection.Map[String, String]): Map[String, String] = {

val combinedMeta: Map[String, Iterable[MetadataElement]] = metadata.map(e => MetadataElement(e._1.replaceFirst("^doc:", ""), e._2, e._1.startsWith("doc:"))).groupBy(_.key)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ class UserListPage extends UserHelper with AdminPageHelper {
".is_admin" #> NodeSeq.Empty &
".enabled *" #> (if (user.enabled.is) "Yes" else "No") &
(if (user.id != current.id) {
".deluser *" #> SHtml.memoize(f => f ++ SHtml.hidden(deleteUser _)) &
".admin_checkbox " #> SHtml.ajaxCheckbox(user.superUser.is, setSuperAdmin(_)) &
".resetpwd *" #> SHtml.memoize(f => f ++ SHtml.hidden(resetPassword _))
".resetpwd [onclick]" #> SHtml.ajaxInvoke(() => resetPassword) &
".deluser [onclick]" #> SHtml.ajaxInvoke(() => deleteUser) &
".admin_checkbox " #> SHtml.ajaxCheckbox(user.superUser.is, setSuperAdmin(_))
} else {
".admin_checkbox" #> NodeSeq.Empty &
".deluser *" #> NodeSeq.Empty &
Expand Down
8 changes: 4 additions & 4 deletions src/main/webapp/groups/files.html
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ <h4 class="modal-title">Настройка прав доступа</h4>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Создать дирректорию</h4>
<h4 class="modal-title">Создать директорию</h4>
</div>
<div class="modal-body">
<form id="new_directory_form" class="form-horizontal">
Expand All @@ -224,15 +224,15 @@ <h4 class="modal-title">Создать дирректорию</h4>
<td><i class="glyphicon glyphicon-font margin-right-glyphicon"></i>Название <span style="color: red;">*</span></td>
<td>
<input class="form-control" type="text" name="name" required
placeholder="Название дирректории">
placeholder="Название директории">
</td>
</tr>
<tr>
<td><i class="glyphicon glyphicon-info-sign margin-right-glyphicon"></i>Описание <span style="color: red;">*</span></td>
<td >
<textarea class="description form-control" cols="500" rows="2" type="text"
name="description" required
placeholder="Описание дирректории"></textarea>
placeholder="Описание директории"></textarea>
</td>
</tr>
<tr >
Expand Down Expand Up @@ -589,7 +589,7 @@ <h3 id="right-box-head" class="panel-title">Select resource</h3>
<div class="row-content">
<h4><i class="glyphicon glyphicon-info-sign"></i> Описание</h4>
<p class="list-group-item-text">
<span class="description_box"></span>
<span id="description_box" style="text-overflow: ellipsis"></span>
</p>
</div>
<hr>
Expand Down
Binary file added src/main/webapp/images/trash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.