mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-11 07:55:55 +01:00
Add Release page. (close #607)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
val Organization = "io.github.gitbucket"
|
||||
val Name = "gitbucket"
|
||||
val GitBucketVersion = "4.11.0"
|
||||
val GitBucketVersion = "4.12.0-SNAPSHOT"
|
||||
val ScalatraVersion = "2.5.0"
|
||||
val JettyVersion = "9.3.9.v20160517"
|
||||
|
||||
|
||||
44
src/main/resources/update/gitbucket-core_4.12.xml
Normal file
44
src/main/resources/update/gitbucket-core_4.12.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<changeSet>
|
||||
<createTable tableName="RELEASE">
|
||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="RELEASE_ID" type="int" nullable="false"/>
|
||||
<column name="NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="TAG" type="varchar(100)" nullable="false"/>
|
||||
<column name="AUTHOR" type="varchar(100)" nullable="false"/>
|
||||
<column name="CONTENT" type="text" nullable="true"/>
|
||||
<column name="IS_DRAFT" type="boolean" nullable="false"/>
|
||||
<column name="IS_PRERELEASE" type="boolean" nullable="false"/>
|
||||
<column name="REGISTERED_DATE" type="datetime" nullable="false"/>
|
||||
<column name="UPDATED_DATE" type="datetime" nullable="false"/>
|
||||
</createTable>
|
||||
|
||||
<addPrimaryKey constraintName="IDX_RELEASE_PK" tableName="RELEASE" columnNames="USER_NAME, REPOSITORY_NAME, RELEASE_ID"/>
|
||||
<addUniqueConstraint constraintName="IDX_RELEASE_UNIQ" tableName="RELEASE" columnNames="USER_NAME, REPOSITORY_NAME, TAG"/>
|
||||
<addForeignKeyConstraint constraintName="IDX_RELEASE_FK0" baseTableName="RELEASE" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME"/>
|
||||
|
||||
<createTable tableName="RELEASE_ID">
|
||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="RELEASE_ID" type="int" nullable="false"/>
|
||||
</createTable>
|
||||
|
||||
<addPrimaryKey constraintName="IDX_RELEASE_ID_PK" tableName="RELEASE_ID" columnNames="USER_NAME, REPOSITORY_NAME"/>
|
||||
<addForeignKeyConstraint constraintName="IDX_RELEASE_ID_FK1" baseTableName="RELEASE_ID" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME"/>
|
||||
|
||||
<createTable tableName="RELEASE_ASSET">
|
||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="RELEASE_ID" type="int" nullable="false"/>
|
||||
<column name="FILE_NAME" type="varchar(260)" nullable="false"/>
|
||||
<column name="LABEL" type="varchar(100)" nullable="true"/>
|
||||
<column name="SIZE" type="bigint" nullable="false"/>
|
||||
<column name="UPLOADER" type="varchar(100)" nullable="false"/>
|
||||
<column name="REGISTERED_DATE" type="datetime" nullable="false"/>
|
||||
<column name="UPDATED_DATE" type="datetime" nullable="false"/>
|
||||
</createTable>
|
||||
<addPrimaryKey constraintName="IDX_RELEASE_ASSET_PK" tableName="RELEASE_ASSET" columnNames="USER_NAME, REPOSITORY_NAME, RELEASE_ID, FILE_NAME"
|
||||
/>
|
||||
<addForeignKeyConstraint constraintName="IDX_RELEASE_ASSET_FK1" baseTableName="RELEASE_ASSET" baseColumnNames="USER_NAME, REPOSITORY_NAME, RELEASE_ID" referencedTableName="RELEASE" referencedColumnNames="USER_NAME, REPOSITORY_NAME, RELEASE_ID"/>
|
||||
</changeSet>
|
||||
@@ -47,6 +47,7 @@ class ScalatraBootstrap extends LifeCycle with SystemSettingsService {
|
||||
context.mount(new MilestonesController, "/*")
|
||||
context.mount(new IssuesController, "/*")
|
||||
context.mount(new PullRequestsController, "/*")
|
||||
context.mount(new ReleaseController, "/*")
|
||||
context.mount(new RepositorySettingsController, "/*")
|
||||
|
||||
// Create GITBUCKET_HOME directory if it does not exist
|
||||
|
||||
@@ -31,5 +31,8 @@ object GitBucketCoreModule extends Module("gitbucket-core",
|
||||
new Version("4.10.0"),
|
||||
new Version("4.11.0",
|
||||
new LiquibaseMigration("update/gitbucket-core_4.11.xml")
|
||||
),
|
||||
new Version("4.12.0",
|
||||
new LiquibaseMigration("update/gitbucket-core_4.12.xml")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.service.{AccountService, RepositoryService}
|
||||
import gitbucket.core.service.{AccountService, RepositoryService, ReleaseService}
|
||||
import gitbucket.core.servlet.Database
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
@@ -20,7 +20,11 @@ import org.apache.commons.io.{FileUtils, IOUtils}
|
||||
*
|
||||
* This servlet saves uploaded file.
|
||||
*/
|
||||
class FileUploadController extends ScalatraServlet with FileUploadSupport with RepositoryService with AccountService {
|
||||
class FileUploadController extends ScalatraServlet
|
||||
with FileUploadSupport
|
||||
with RepositoryService
|
||||
with AccountService
|
||||
with ReleaseService{
|
||||
|
||||
configureMultipartHandling(MultipartConfig(maxFileSize = Some(3 * 1024 * 1024)))
|
||||
|
||||
@@ -78,6 +82,25 @@ class FileUploadController extends ScalatraServlet with FileUploadSupport with R
|
||||
} getOrElse BadRequest()
|
||||
}
|
||||
|
||||
post("/release/:owner/:repository/:id"){
|
||||
session.get(Keys.Session.LoginAccount).collect { case loginAccount: Account =>
|
||||
val owner = params("owner")
|
||||
val repository = params("repository")
|
||||
val releaseId = params("id").toInt
|
||||
val release = getRelease(owner, repository, releaseId)
|
||||
execute({ (file, fileId) =>
|
||||
val fileName = file.getName
|
||||
release.map { rel =>
|
||||
createReleaseAsset(owner, repository, releaseId, fileId, fileName, file.size, loginAccount)
|
||||
FileUtils.writeByteArrayToFile(new java.io.File(
|
||||
getReleaseFilesDir(owner, repository) + s"/${rel.tag}",
|
||||
fileId), file.get)
|
||||
fileName
|
||||
}
|
||||
}, (_ => true))
|
||||
}.getOrElse(BadRequest())
|
||||
}
|
||||
|
||||
post("/import") {
|
||||
import JDBCUtil._
|
||||
session.get(Keys.Session.LoginAccount).collect { case loginAccount: Account if loginAccount.isAdmin =>
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.service.{RepositoryService, AccountService, ReleaseService, ActivityService}
|
||||
import gitbucket.core.util.{ReferrerAuthenticator, ReadableUsersAuthenticator, WritableUsersAuthenticator, FileUtil, Notifier}
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
import gitbucket.core.view.Markdown
|
||||
import io.github.gitbucket.scalatra.forms._
|
||||
import gitbucket.core.releases.html
|
||||
|
||||
class ReleaseController extends ReleaseControllerBase
|
||||
with RepositoryService
|
||||
with AccountService
|
||||
with ReleaseService
|
||||
with ActivityService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator
|
||||
|
||||
trait ReleaseControllerBase extends ControllerBase {
|
||||
self: RepositoryService
|
||||
with AccountService
|
||||
with ReleaseService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator
|
||||
with ActivityService =>
|
||||
|
||||
case class ReleaseCreateForm(
|
||||
name: String,
|
||||
content: Option[String],
|
||||
isPrerelease: Boolean
|
||||
)
|
||||
|
||||
val releaseCreateForm = mapping(
|
||||
"name" -> trim(text(required)),
|
||||
"content" -> trim(optional(text())),
|
||||
"isprerelease" -> boolean()
|
||||
)(ReleaseCreateForm.apply)
|
||||
|
||||
val releaseTitleEditForm = mapping(
|
||||
"title" -> trim(label("Title", text(required)))
|
||||
)(x => x)
|
||||
|
||||
val releaseEditForm = mapping(
|
||||
"content" -> trim(optional(text()))
|
||||
)(x => x)
|
||||
|
||||
get("/:owner/:repository/releases")(referrersOnly {repository =>
|
||||
html.list(
|
||||
repository,
|
||||
getReleaseTagMap(repository.owner, repository.name),
|
||||
getReleaseAssetsMap(repository.owner, repository.name),
|
||||
hasDeveloperRole(repository.owner, repository.name, context.loginAccount))
|
||||
})
|
||||
|
||||
get("/:owner/:repository/releases/:id")(referrersOnly {repository =>
|
||||
val id = params("id")
|
||||
getRelease(repository.owner, repository.name, id).map{ release =>
|
||||
html.release(release, getReleaseAssets(repository.owner, repository.name, id), hasDeveloperRole(repository.owner, repository.name, context.loginAccount), repository)
|
||||
}.getOrElse(NotFound())
|
||||
})
|
||||
|
||||
get("/:owner/:repository/releases/:id/assets/:fileId")(referrersOnly {repository =>
|
||||
val releaseId = params("id")
|
||||
val fileId = params("fileId")
|
||||
getRelease(repository.owner, repository.name, releaseId).flatMap{ release =>
|
||||
getReleaseAsset(repository.owner, repository.name, releaseId, fileId).flatMap{ asset =>
|
||||
response.setHeader("Content-Disposition", s"attachment; filename=${asset.label}")
|
||||
Some(RawData(FileUtil.getMimeType(asset.label), new java.io.File(getReleaseFilesDir(repository.owner, repository.name) + s"/${release.tag}", fileId)))
|
||||
}
|
||||
}.getOrElse(NotFound())
|
||||
})
|
||||
|
||||
get("/:owner/:repository/releases/:tag/create")(writableUsersOnly {repository =>
|
||||
val tag = params("tag")
|
||||
defining(repository.owner, repository.name){ case (owner, name) =>
|
||||
html.create(repository, tag)
|
||||
}
|
||||
})
|
||||
|
||||
post("/:owner/:repository/releases/:tag/create", releaseCreateForm)(writableUsersOnly { (form, repository) =>
|
||||
val tag = params("tag")
|
||||
val release = createRelease(repository, form.name, form.content, tag, false, form.isPrerelease, context.loginAccount.get)
|
||||
recordReleaseActivity(repository.owner, repository.name, context.loginAccount.get.userName, release.releaseId, release.name)
|
||||
|
||||
redirect(s"/${release.userName}/${release.repositoryName}/releases/${release.releaseId}")
|
||||
})
|
||||
|
||||
get("/:owner/:repository/release/delete/:id")(writableUsersOnly { repository =>
|
||||
deleteRelease(repository.owner, repository.name, params("id"))
|
||||
|
||||
redirect(s"/${repository.owner}/${repository.name}/releases")
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/releases/edit_title/:id", releaseTitleEditForm)(writableUsersOnly { (title, repository) =>
|
||||
defining(repository.owner, repository.name) { case (owner, name) =>
|
||||
getRelease(owner, name, params("id")).map { release =>
|
||||
updateRelease(owner, name, release.releaseId, title, release.content)
|
||||
redirect(s"/${owner}/${name}/releases/_data/${release.releaseId}")
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/releases/edit/:id", releaseEditForm)(writableUsersOnly { (content, repository) =>
|
||||
defining(repository.owner, repository.name){ case (owner, name) =>
|
||||
getRelease(owner, name, params("id")).map { release =>
|
||||
updateRelease(owner, name, release.releaseId, release.name, content)
|
||||
redirect(s"/${owner}/${name}/releases/_data/${release.releaseId}")
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
ajaxGet("/:owner/:repository/releases/_data/:id")(writableUsersOnly { repository =>
|
||||
getRelease(repository.owner, repository.name, params("id")) map { x =>
|
||||
params.get("dataType") collect {
|
||||
case t if t == "html" => html.editrelease(x.content, x.releaseId, repository)
|
||||
} getOrElse {
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"title" -> x.name,
|
||||
"content" -> Markdown.toHtml(
|
||||
markdown = x.content getOrElse "No description given.",
|
||||
repository = repository,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableAnchor = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
}
|
||||
@@ -63,4 +63,15 @@ protected[model] trait TemplateComponent { self: Profile =>
|
||||
def byBranch(owner: String, repository: String, branchName: String) = byRepository(owner, repository) && (branch === branchName.bind)
|
||||
def byBranch(owner: Rep[String], repository: Rep[String], branchName: Rep[String]) = byRepository(owner, repository) && (this.branch === branchName)
|
||||
}
|
||||
|
||||
trait ReleaseTemplate extends BasicTemplate { self: Table[_] =>
|
||||
val releaseId = column[Int]("RELEASE_ID")
|
||||
|
||||
def byRelease(owner: String, repository: String, releaseId: Int) =
|
||||
byRepository(owner, repository) && (this.releaseId === releaseId.bind)
|
||||
|
||||
def byRelease(userName: Rep[String], repositoryName: Rep[String], releaseId: Rep[Int]) =
|
||||
byRepository(userName, repositoryName) && (this.releaseId === releaseId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,5 +55,7 @@ trait CoreProfile extends ProfileProvider with Profile
|
||||
with WebHookEventComponent
|
||||
with ProtectedBranchComponent
|
||||
with DeployKeyComponent
|
||||
with ReleaseComponent
|
||||
with ReleaseAssetComponent
|
||||
|
||||
object Profile extends CoreProfile
|
||||
|
||||
53
src/main/scala/gitbucket/core/model/Release.scala
Normal file
53
src/main/scala/gitbucket/core/model/Release.scala
Normal file
@@ -0,0 +1,53 @@
|
||||
package gitbucket.core.model
|
||||
|
||||
trait ReleaseComponent extends TemplateComponent {
|
||||
self: Profile =>
|
||||
|
||||
import profile.api._
|
||||
import self._
|
||||
|
||||
lazy val ReleaseId = TableQuery[ReleaseId]
|
||||
lazy val Releases = TableQuery[Releases]
|
||||
|
||||
class ReleaseId(tag: Tag) extends Table[(String, String, Int)](tag, "RELEASE_ID") with ReleaseTemplate {
|
||||
def * = (userName, repositoryName, releaseId)
|
||||
|
||||
def byPrimaryKey(owner: String, repository: String) = byRepository(owner, repository)
|
||||
}
|
||||
|
||||
class Releases(tag_ : Tag) extends Table[Release](tag_, "RELEASE") with ReleaseTemplate {
|
||||
val name = column[String]("NAME")
|
||||
val tag = column[String]("TAG")
|
||||
val author = column[String]("AUTHOR")
|
||||
val content = column[Option[String]]("CONTENT")
|
||||
val isDraft = column[Boolean]("IS_DRAFT")
|
||||
val isPrerelease = column[Boolean]("IS_PRERELEASE")
|
||||
val registeredDate = column[java.util.Date]("REGISTERED_DATE")
|
||||
val updatedDate = column[java.util.Date]("UPDATED_DATE")
|
||||
|
||||
def * = (userName, repositoryName, releaseId, name, tag, author, content, isDraft, isPrerelease, registeredDate, updatedDate) <> (Release.tupled, Release.unapply)
|
||||
|
||||
def byPrimaryKey(owner: String, repository: String, releaseId: Int) = byRelease(owner, repository, releaseId)
|
||||
|
||||
def byTag(owner: String, repository: String, tag: String) =
|
||||
byRepository(owner, repository) && (this.tag === tag.bind)
|
||||
|
||||
def byTag(userName: Rep[String], repositoryName: Rep[String], tag: Rep[String]) =
|
||||
byRepository(userName, repositoryName) && (this.tag === tag)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case class Release(
|
||||
userName: String,
|
||||
repositoryName: String,
|
||||
releaseId: Int = 0,
|
||||
name: String,
|
||||
tag: String,
|
||||
author: String,
|
||||
content: Option[String],
|
||||
isDraft: Boolean,
|
||||
isPrerelease: Boolean,
|
||||
registeredDate: java.util.Date,
|
||||
updatedDate: java.util.Date
|
||||
)
|
||||
38
src/main/scala/gitbucket/core/model/ReleasesAsset.scala
Normal file
38
src/main/scala/gitbucket/core/model/ReleasesAsset.scala
Normal file
@@ -0,0 +1,38 @@
|
||||
package gitbucket.core.model
|
||||
|
||||
import java.util.Date
|
||||
|
||||
trait ReleaseAssetComponent extends TemplateComponent {
|
||||
self: Profile =>
|
||||
|
||||
import profile.api._
|
||||
import self._
|
||||
|
||||
lazy val ReleaseAssets = TableQuery[ReleaseAssets]
|
||||
|
||||
class ReleaseAssets(tag : Tag) extends Table[ReleaseAsset](tag, "RELEASE_ASSET") with ReleaseTemplate {
|
||||
val fileName = column[String]("FILE_NAME")
|
||||
val label = column[String]("LABEL")
|
||||
val size = column[Long]("SIZE")
|
||||
val uploader = column[String]("UPLOADER")
|
||||
val registeredDate = column[Date]("REGISTERED_DATE")
|
||||
val updatedDate = column[Date]("UPDATED_DATE")
|
||||
|
||||
def * = (userName, repositoryName, releaseId, fileName, label, size, uploader, registeredDate, updatedDate) <> (ReleaseAsset.tupled, ReleaseAsset.unapply)
|
||||
|
||||
def byPrimaryKey(owner: String, repository: String, releaseId: Int, fileName: String) = byRelease(owner, repository, releaseId) && (this.fileName === fileName.bind)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case class ReleaseAsset(
|
||||
userName: String,
|
||||
repositoryName: String,
|
||||
releaseId: Int,
|
||||
fileName: String,
|
||||
label: String,
|
||||
size: Long,
|
||||
uploader: String,
|
||||
registeredDate: Date,
|
||||
updatedDate: Date
|
||||
)
|
||||
@@ -59,7 +59,7 @@ trait ActivityService {
|
||||
Activities insert Activity(userName, repositoryName, activityUserName,
|
||||
"open_issue",
|
||||
s"[user:${activityUserName}] opened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||
Some(title),
|
||||
Some(title),
|
||||
currentDate)
|
||||
|
||||
def recordCloseIssueActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, title: String)
|
||||
@@ -135,7 +135,7 @@ trait ActivityService {
|
||||
Some(commits.map { commit => commit.id + ":" + commit.shortMessage }.mkString("\n")),
|
||||
currentDate)
|
||||
|
||||
def recordCreateTagActivity(userName: String, repositoryName: String, activityUserName: String,
|
||||
def recordCreateTagActivity(userName: String, repositoryName: String, activityUserName: String,
|
||||
tagName: String, commits: List[JGitUtil.CommitInfo])(implicit s: Session): Unit =
|
||||
Activities insert Activity(userName, repositoryName, activityUserName,
|
||||
"create_tag",
|
||||
@@ -167,7 +167,7 @@ trait ActivityService {
|
||||
None,
|
||||
currentDate)
|
||||
|
||||
def recordForkActivity(userName: String, repositoryName: String, activityUserName: String, forkedUserName: String)(implicit s: Session): Unit =
|
||||
def recordForkActivity(userName: String, repositoryName: String, activityUserName: String, forkedUserName: String)(implicit s: Session): Unit =
|
||||
Activities insert Activity(userName, repositoryName, activityUserName,
|
||||
"fork",
|
||||
s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${forkedUserName}/${repositoryName}]",
|
||||
@@ -190,6 +190,13 @@ trait ActivityService {
|
||||
Some(message),
|
||||
currentDate)
|
||||
|
||||
def recordReleaseActivity(userName: String, repositoryName: String, activityUserName: String, releaseId: Int, name: String)(implicit s: Session): Unit =
|
||||
Activities insert Activity(userName, repositoryName, activityUserName,
|
||||
"release",
|
||||
s"[user:${activityUserName}] released ${name} at [repo:${userName}/${repositoryName}]",
|
||||
None,
|
||||
currentDate)
|
||||
|
||||
private def cut(value: String, length: Int): String =
|
||||
if(value.length > length) value.substring(0, length) + "..." else value
|
||||
}
|
||||
|
||||
129
src/main/scala/gitbucket/core/service/ReleaseService.scala
Normal file
129
src/main/scala/gitbucket/core/service/ReleaseService.scala
Normal file
@@ -0,0 +1,129 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.model.{Account, Release, ReleaseAsset}
|
||||
import gitbucket.core.util.StringUtil._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile._
|
||||
import gitbucket.core.model.Profile.dateColumnType
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
|
||||
trait ReleaseService {
|
||||
self: AccountService with RepositoryService =>
|
||||
|
||||
def createReleaseAsset(owner: String, repository: String, releaseId: Int, fileName: String, label: String, size: Long, loginAccount: Account)(implicit s: Session): Unit = {
|
||||
ReleaseAssets insert ReleaseAsset(
|
||||
owner,
|
||||
repository,
|
||||
releaseId,
|
||||
fileName,
|
||||
label,
|
||||
size,
|
||||
loginAccount.userName,
|
||||
currentDate,
|
||||
currentDate
|
||||
)
|
||||
}
|
||||
|
||||
def getReleaseAssets(owner: String, repository: String, releaseId: Int)(implicit s: Session): List[ReleaseAsset] = {
|
||||
ReleaseAssets.filter(x => x.byRelease(owner, repository, releaseId)).list
|
||||
}
|
||||
|
||||
def getReleaseAssets(owner: String, repository: String, releaseId: String)(implicit s: Session): List[ReleaseAsset] = {
|
||||
if (isInteger(releaseId))
|
||||
getReleaseAssets(owner, repository, releaseId.toInt)
|
||||
else
|
||||
List.empty
|
||||
}
|
||||
|
||||
def getReleaseAssetsMap(owner: String, repository: String)(implicit s: Session): Map[Release, List[ReleaseAsset]] = {
|
||||
val releases = getReleases(owner, repository)
|
||||
releases.map(rel => (rel -> getReleaseAssets(owner, repository, rel.releaseId))).toMap
|
||||
}
|
||||
|
||||
def getReleaseAsset(owner: String, repository: String, releaseId: String, fileId: String)(implicit s: Session): Option[ReleaseAsset] = {
|
||||
if (isInteger(releaseId))
|
||||
ReleaseAssets.filter(x => x.byPrimaryKey(owner, repository, releaseId.toInt, fileId)) firstOption
|
||||
else None
|
||||
}
|
||||
|
||||
def deleteReleaseAssets(owner: String, repository: String, releaseId: Int)(implicit s: Session): Unit = {
|
||||
ReleaseAssets.filter(x => x.byRelease(owner, repository, releaseId)) delete
|
||||
}
|
||||
|
||||
def createRelease(repository: RepositoryInfo, name: String, content:Option[String], tag: String,
|
||||
isDraft: Boolean, isPrerelease: Boolean, loginAccount: Account)(implicit context: Context, s: Session): Release = {
|
||||
val releaseId = insertRelease(repository.owner, repository.name, loginAccount.userName, name, tag,
|
||||
content, isDraft, isPrerelease)
|
||||
val release = getRelease(repository.owner, repository.name, releaseId.toString).get
|
||||
release
|
||||
}
|
||||
|
||||
def getReleases(owner: String, repository: String)(implicit s: Session): List[Release] = {
|
||||
Releases.filter(x => x.byRepository(owner, repository)).list
|
||||
}
|
||||
|
||||
def getRelease(owner: String, repository: String, releaseId: Int)(implicit s: Session): Option[Release] = {
|
||||
Releases filter (_.byPrimaryKey(owner, repository, releaseId)) firstOption
|
||||
}
|
||||
|
||||
def getRelease(owner: String, repository: String, releaseId: String)(implicit s: Session): Option[Release] = {
|
||||
if (isInteger(releaseId))
|
||||
getRelease(owner, repository, releaseId.toInt)
|
||||
else None
|
||||
}
|
||||
|
||||
def getReleaseTagMap(owner: String, repository: String)(implicit s: Session): Map[String, Release] = {
|
||||
val releases = getReleases(owner, repository)
|
||||
releases.map(rel => (rel.tag -> rel)).toMap
|
||||
}
|
||||
|
||||
def insertRelease(owner: String, repository: String, loginUser: String, name: String, tag: String,
|
||||
content: Option[String], isDraft: Boolean, isPrerelease: Boolean)(implicit s: Session): Int = {
|
||||
// next id number
|
||||
val id = sql"SELECT RELEASE_ID + 1 FROM RELEASE_ID WHERE USER_NAME = $owner AND REPOSITORY_NAME = $repository FOR UPDATE".as[Int]
|
||||
.firstOption.getOrElse(1)
|
||||
Releases insert Release(
|
||||
owner,
|
||||
repository,
|
||||
id,
|
||||
name,
|
||||
tag,
|
||||
loginUser,
|
||||
content,
|
||||
isDraft,
|
||||
isPrerelease,
|
||||
currentDate,
|
||||
currentDate
|
||||
)
|
||||
|
||||
// increment issue id
|
||||
if (id > 1){
|
||||
ReleaseId
|
||||
.filter(_.byPrimaryKey(owner, repository))
|
||||
.map(_.releaseId)
|
||||
.update(id) > 0
|
||||
}else{
|
||||
ReleaseId.insert(owner, repository, id)
|
||||
}
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
def updateRelease(owner: String, repository: String, releaseId: Int, title: String, content: Option[String])(implicit s: Session): Int = {
|
||||
Releases
|
||||
.filter (_.byPrimaryKey(owner, repository, releaseId))
|
||||
.map { t => (t.name, t.content, t.updatedDate) }
|
||||
.update (title, content, currentDate)
|
||||
}
|
||||
|
||||
def deleteRelease(owner: String, repository: String, releaseId: String)(implicit s: Session): Unit = {
|
||||
if (isInteger(releaseId)){
|
||||
val relId = releaseId.toInt
|
||||
deleteReleaseAssets(owner, repository, relId)
|
||||
Releases filter (_.byPrimaryKey(owner, repository, relId)) delete
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package gitbucket.core.service
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
import gitbucket.core.model.{Account, Collaborator, Repository, RepositoryOptions, Role}
|
||||
import gitbucket.core.model.{Account, Collaborator, Repository, RepositoryOptions, Role, Release}
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.Profile.dateColumnType
|
||||
@@ -216,6 +216,10 @@ trait RepositoryService { self: AccountService =>
|
||||
t.byRepository(repository.userName, repository.repositoryName) && (t.closed === false.bind)
|
||||
}.map(_.pullRequest).list
|
||||
|
||||
val releases = Releases.filter { t =>
|
||||
t.byRepository(repository.userName, repository.repositoryName)
|
||||
}.list
|
||||
|
||||
new RepositoryInfo(
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName),
|
||||
repository,
|
||||
@@ -225,6 +229,7 @@ trait RepositoryService { self: AccountService =>
|
||||
repository.originUserName.getOrElse(repository.userName),
|
||||
repository.originRepositoryName.getOrElse(repository.repositoryName)
|
||||
),
|
||||
releases.length,
|
||||
getRepositoryManagers(repository.userName))
|
||||
}
|
||||
}
|
||||
@@ -458,20 +463,20 @@ trait RepositoryService { self: AccountService =>
|
||||
object RepositoryService {
|
||||
|
||||
case class RepositoryInfo(owner: String, name: String, repository: Repository,
|
||||
issueCount: Int, pullCount: Int, forkedCount: Int,
|
||||
issueCount: Int, pullCount: Int, forkedCount: Int, releaseCount: Int,
|
||||
branchList: Seq[String], tags: Seq[JGitUtil.TagInfo], managers: Seq[String]) {
|
||||
|
||||
/**
|
||||
* Creates instance with issue count and pull request count.
|
||||
*/
|
||||
def this(repo: JGitUtil.RepositoryInfo, model: Repository, issueCount: Int, pullCount: Int, forkedCount: Int, managers: Seq[String]) =
|
||||
this(repo.owner, repo.name, model, issueCount, pullCount, forkedCount, repo.branchList, repo.tags, managers)
|
||||
def this(repo: JGitUtil.RepositoryInfo, model: Repository, issueCount: Int, pullCount: Int, forkedCount: Int, releaseCount: Int, managers: Seq[String]) =
|
||||
this(repo.owner, repo.name, model, issueCount, pullCount, forkedCount, releaseCount, repo.branchList, repo.tags, managers)
|
||||
|
||||
/**
|
||||
* Creates instance without issue count and pull request count.
|
||||
* Creates instance without issue, pull request and release count.
|
||||
*/
|
||||
def this(repo: JGitUtil.RepositoryInfo, model: Repository, forkedCount: Int, managers: Seq[String]) =
|
||||
this(repo.owner, repo.name, model, 0, 0, forkedCount, repo.branchList, repo.tags, managers)
|
||||
this(repo.owner, repo.name, model, 0, 0, forkedCount, 0, repo.branchList, repo.tags, managers)
|
||||
|
||||
def httpUrl(implicit context: Context): String = RepositoryService.httpUrl(owner, name)
|
||||
def sshUrl(implicit context: Context): Option[String] = RepositoryService.sshUrl(owner, name)
|
||||
|
||||
@@ -54,6 +54,12 @@ object Directory {
|
||||
def getAttachedDir(owner: String, repository: String): File =
|
||||
new File(getRepositoryFilesDir(owner, repository), "comments")
|
||||
|
||||
/**
|
||||
* Directory for released files
|
||||
*/
|
||||
def getReleaseFilesDir(owner: String, repository: String): File =
|
||||
new File(getRepositoryFilesDir(owner, repository), "releases")
|
||||
|
||||
/**
|
||||
* Directory for files which are attached to issue.
|
||||
*/
|
||||
@@ -90,4 +96,4 @@ object Directory {
|
||||
def getWikiRepositoryDir(owner: String, repository: String): File =
|
||||
new File(s"${RepositoryHome}/${owner}/${repository}.wiki.git")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
case "reopen_issue" => detailActivity(activity, "issue-reopened")
|
||||
case "open_pullreq" => detailActivity(activity, "git-pull-request")
|
||||
case "merge_pullreq" => detailActivity(activity, "git-merge")
|
||||
case "release" => detailActivity(activity, "package")
|
||||
case "create_repository" => simpleActivity(activity, "repo")
|
||||
case "create_branch" => simpleActivity(activity, "git-branch")
|
||||
case "delete_branch" => simpleActivity(activity, "circle-slash")
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
@menuitem("/branches", "branches", "Branches", "git-branch", repository.branchList.length)
|
||||
@menuitem("/tags", "tags", "Tags", "tag", repository.tags.length)
|
||||
}
|
||||
@menuitem("/releases", "releases", "Releases", "package", repository.releaseCount)
|
||||
@if(repository.repository.options.issuesOption != "DISABLE") {
|
||||
@menuitem("/issues", "issues", "Issues", "issue-opened", repository.issueCount)
|
||||
@menuitem("/pulls", "pulls", "Pull requests", "git-pull-request", repository.pullCount)
|
||||
|
||||
33
src/main/twirl/gitbucket/core/releases/create.scala.html
Normal file
33
src/main/twirl/gitbucket/core/releases/create.scala.html
Normal file
@@ -0,0 +1,33 @@
|
||||
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo, tag: String)(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
@gitbucket.core.html.main(s"New Release - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<form action="@helpers.url(repository)/releases/@tag/create" method="POST" validate="true" class="form-group">
|
||||
<div class="row-fluid">
|
||||
<div class="col-md-9">
|
||||
<h3>New release for @tag</h3>
|
||||
<span id="error-title" class="error"></span>
|
||||
<input type="text" id="release-name" name="name" class="form-control" value="" placeholder="Title" style="margin-bottom: 6px;" autofocus/>
|
||||
@gitbucket.core.helper.html.preview(
|
||||
repository = repository,
|
||||
content = "",
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true,
|
||||
completionContext = "releases",
|
||||
style = "height: 200px; max-height: 500px;",
|
||||
elastic = true,
|
||||
placeholder = "Describe this release"
|
||||
)
|
||||
<input type="checkbox" id="release-isprerelease" name="isprerelease"/>
|
||||
<label for="release-isprerelease">This is a pre-release</label>
|
||||
<div class="align-right">
|
||||
<input type="submit" class="btn btn-success" value="Submit new release"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
@(content: Option[String], releaseId: Int,
|
||||
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
|
||||
@gitbucket.core.helper.html.attached(repository, "releases"){
|
||||
<textarea id="edit-content" class="form-control">@content.getOrElse("")</textarea>
|
||||
}
|
||||
<div>
|
||||
<input type="button" id="cancel-release" class="btn btn-danger" value="Cancel"/>
|
||||
<input type="button" id="update-release" class="btn btn-default pull-right" value="Update comment"/>
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
var callback = function(data){
|
||||
$('#update, #cancel').removeAttr('disabled');
|
||||
$('#release-note').empty().html(data.content);
|
||||
};
|
||||
|
||||
$('#update-release').click(function(){
|
||||
$('#update, #cancel').attr('disabled', 'disabled');
|
||||
$.ajax({
|
||||
url: '@context.path/@repository.owner/@repository.name/releases/edit/@releaseId',
|
||||
type: 'POST',
|
||||
data: {
|
||||
content : $('#edit-content').val()
|
||||
}
|
||||
}).done(
|
||||
callback
|
||||
).fail(function(req) {
|
||||
$('#update, #cancel').removeAttr('disabled');
|
||||
});
|
||||
});
|
||||
|
||||
$('#cancel-release').click(function(){
|
||||
$('#update, #cancel').attr('disabled', 'disabled');
|
||||
$.get('@context.path/@repository.owner/@repository.name/releases/_data/@releaseId', callback);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
69
src/main/twirl/gitbucket/core/releases/list.scala.html
Normal file
69
src/main/twirl/gitbucket/core/releases/list.scala.html
Normal file
@@ -0,0 +1,69 @@
|
||||
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
||||
tagReleaseMap: Map[String, gitbucket.core.model.Release],
|
||||
releaseAssetsMap: Map[gitbucket.core.model.Release, List[gitbucket.core.model.ReleaseAsset]],
|
||||
hasWritePermission: Boolean)(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
@gitbucket.core.html.main("Releases" + s" - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<table class="table table-bordered table-releases">
|
||||
<thead>
|
||||
<tr><th>@tagReleaseMap.count(_ => true) releases</div></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@repository.tags.reverse.map{ tag =>
|
||||
<tr>
|
||||
<td>
|
||||
@tagReleaseMap.get(tag.name).map{rel =>
|
||||
<div class="col-md-1"><a href="@helpers.url(repository)/tree/@tag.name"><i class="octicon octicon-tag"></i>@tag.name</a></div>
|
||||
<div class="col-md-11" style="border-left: 1px solid #eee">
|
||||
<h3><a href="@helpers.url(repository)/releases/@rel.releaseId">@rel.name</a></h3>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="muted">
|
||||
@helpers.avatar(rel.author, 20)
|
||||
@helpers.user(rel.author, styleClass="username strong")
|
||||
released this @gitbucket.core.helper.html.datetimeago(rel.registeredDate)
|
||||
</span>
|
||||
</div>
|
||||
<div class="panel-body release-note markdown-body">
|
||||
@helpers.markdown(
|
||||
markdown = rel.content getOrElse "No description provided.",
|
||||
repository = repository,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission
|
||||
)
|
||||
</div>
|
||||
<h2>Downloads</h2>
|
||||
<ul style="list-style: none">
|
||||
@releaseAssetsMap(rel).map{ asset =>
|
||||
<li><i class="octicon octicon-file"></i><a href="@helpers.url(repository)/releases/@rel.releaseId/assets/@asset.fileName">@asset.label</a></li>
|
||||
}
|
||||
</ul>
|
||||
<ul style="list-style: none;">
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(rel.tag)}.zip"><i class="octicon octicon-file-zip"></i>ZIP</a></li>
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(rel.tag)}.tar.gz"><i class="octicon octicon-file-zip"></i>TAR.GZ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
}.getOrElse{
|
||||
<div class="col-md-1">
|
||||
@gitbucket.core.helper.html.datetimeago(tag.time) <i class="octicon octicon-tag"></i>
|
||||
</div>
|
||||
<div class="col-md-11" style="border-left: 1px solid #eee">
|
||||
<a href="@helpers.url(repository)/tree/@tag.name"><i class="octicon octicon-tag"></i>@tag.name</a>
|
||||
@if(hasWritePermission){
|
||||
<div class="show-title pull-right">
|
||||
<a class="btn btn-success" href="@helpers.url(repository)/releases/@tag.name/create">Create release</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}}
|
||||
151
src/main/twirl/gitbucket/core/releases/release.scala.html
Normal file
151
src/main/twirl/gitbucket/core/releases/release.scala.html
Normal file
@@ -0,0 +1,151 @@
|
||||
@(release: gitbucket.core.model.Release,
|
||||
assets: List[gitbucket.core.model.ReleaseAsset],
|
||||
hasWritePermission: Boolean,
|
||||
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
@gitbucket.core.html.main(s"${release.name} - Release ${release.releaseId} - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<div class="row">
|
||||
<div class="col-md-1">
|
||||
<div><a href="@helpers.url(repository)/tree/@release.tag"><i class="octicon octicon-tag"></i>@release.tag</a></div>
|
||||
</div>
|
||||
<div class="col-md-11" style="border-left: 1px solid #eee">
|
||||
<div>
|
||||
<div class="show-title pull-right">
|
||||
@if(hasWritePermission){
|
||||
<a class="btn btn-default" href="#" id="edit">Edit title</a>
|
||||
<a class="btn btn-danger" href="#" id="delete-release">Delete</a>
|
||||
}
|
||||
</div>
|
||||
<div class="edit-title pull-right" style="display: none;">
|
||||
<a class="btn btn-success" href="#" id="update">Save</a> <a class="btn btn-default" href="#" id="cancel">Cancel</a>
|
||||
</div>
|
||||
<h1 class="body-title">
|
||||
<span class="show-title">
|
||||
<span id="show-title">@release.name</span>
|
||||
</span>
|
||||
<span class="edit-title" style="display: none;">
|
||||
<span id="error-edit-title" class="error"></span>
|
||||
<input type="text" class="form-control" style="width: 700px;" id="edit-title" value="@release.name"/>
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="muted">
|
||||
@helpers.avatar(release.author, 20)
|
||||
@helpers.user(release.author, styleClass="username strong") released this @gitbucket.core.helper.html.datetimeago(release.registeredDate)
|
||||
</span>
|
||||
<span class="pull-right">
|
||||
@if(hasWritePermission){
|
||||
<a href="#"><i class="octicon octicon-pencil" aria-label="Edit" id="edit-notes"></i></a>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
<div class="panel-body markdown-body" id="release-note">
|
||||
@helpers.markdown(
|
||||
markdown = release.content getOrElse "No description provided.",
|
||||
repository = repository,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission
|
||||
)
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h2>Downloads</h2>
|
||||
@if(hasWritePermission){
|
||||
<div style="border: 3px dashed #ccc; background-color: #eee" >
|
||||
<div id="drop" class="clickable">Attach release files by dragging & dropping, or selecting them.</div>
|
||||
</div>
|
||||
}
|
||||
<ul style="list-style: none;" id="attachedFiles">
|
||||
@assets.map{ asset =>
|
||||
<li>
|
||||
<i class="octicon octicon-file"></i>
|
||||
<a href="@helpers.url(repository)/releases/@release.releaseId/assets/@asset.fileName">@asset.label</a>
|
||||
<span class="label label-default">@helpers.readableSize(Some(asset.size))</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<ul style="list-style: none;">
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(release.tag)}.zip"><i class="octicon octicon-file-zip"></i>ZIP</a></li>
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(release.tag)}.tar.gz"><i class="octicon octicon-file-zip"></i>TAR.GZ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
$('#edit').click(function(){
|
||||
$('.edit-title').show();
|
||||
$('.show-title').hide();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#update').click(function(){
|
||||
$(this).attr('disabled', 'disabled');
|
||||
$.ajax({
|
||||
url: '@helpers.url(repository)/releases/edit_title/@release.releaseId',
|
||||
type: 'POST',
|
||||
data: {
|
||||
title : $('#edit-title').val()
|
||||
}
|
||||
}).done(function(data){
|
||||
$('#show-title').empty().text(data.title);
|
||||
$('#cancel').click();
|
||||
$(this).removeAttr('disabled');
|
||||
}).fail(function(req){
|
||||
$(this).removeAttr('disabled');
|
||||
$('#error-edit-title').text($.parseJSON(req.responseText).title);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#cancel').click(function(){
|
||||
$('.edit-title').hide();
|
||||
$('.show-title').show();
|
||||
return false;
|
||||
});
|
||||
$('#edit-notes').click(function(){
|
||||
var id = @release.releaseId;
|
||||
var url = '@helpers.url(repository)/releases/_data/' + id;
|
||||
var $content = $('#release-note');
|
||||
|
||||
$.get(url,
|
||||
{
|
||||
dataType : 'html'
|
||||
},
|
||||
function(data){
|
||||
$content.empty().html(data);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
$('#delete-release').click(function(){
|
||||
if(confirm('Are you sure you want to delete this?')) {
|
||||
var id = $(this).closest('a').data('comment-id');
|
||||
$.post('@helpers.url(repository)/issue_comments/delete/' + id,
|
||||
function(data){
|
||||
if(data > 0) {
|
||||
$('#comment-' + id).prev('div.issue-avatar-image').remove();
|
||||
$('#comment-' + id).remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
$("#drop").dropzone({
|
||||
url: '@context.path/upload/release/@repository.owner/@repository.name/@release.releaseId',
|
||||
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
||||
success: function(file, id) {
|
||||
var attach = '<li><a href="@context.baseUrl/@repository.owner/@repository.name/_release/@release.releaseId/' + id + '">'
|
||||
+ '<i class="octicon octicon-file"></i>' + file.name + '</a></li>';
|
||||
$('#attachedFiles').append(attach);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user