mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-02 19:45:57 +01:00
(refs #4)Add 'Public Activity' tab to the account information page.
This commit is contained in:
12
src/main/resources/update/1_2.sql
Normal file
12
src/main/resources/update/1_2.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
CREATE TABLE ACTIVITY(
|
||||
ACTIVITY_ID INT AUTO_INCREMENT,
|
||||
USER_NAME VARCHAR(100) NOT NULL,
|
||||
REPOSITORY_NAME VARCHAR(100) NOT NULL,
|
||||
ACTIVITY_USER_NAME VARCHAR(100) NOT NULL,
|
||||
MESSAGE TEXT NOT NULL,
|
||||
ACTIVITY_DATE TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE ACTIVITY ADD CONSTRAINT IDX_ACTIVITY_PK PRIMARY KEY (ACTIVITY_ID);
|
||||
ALTER TABLE ACTIVITY ADD CONSTRAINT IDX_ACTIVITY_FK0 FOREIGN KEY (USER_NAME, REPOSITORY_NAME) REFERENCES REPOSITORY (USER_NAME, REPOSITORY_NAME);
|
||||
ALTER TABLE ACTIVITY ADD CONSTRAINT IDX_ACTIVITY_FK1 FOREIGN KEY (ACTIVITY_USER_NAME) REFERENCES ACCOUNT (USER_NAME);
|
||||
@@ -6,10 +6,12 @@ import util.StringUtil._
|
||||
import jp.sf.amateras.scalatra.forms._
|
||||
|
||||
class AccountController extends AccountControllerBase
|
||||
with SystemSettingsService with AccountService with RepositoryService with OneselfAuthenticator
|
||||
with SystemSettingsService with AccountService with RepositoryService with ActivityService
|
||||
with OneselfAuthenticator
|
||||
|
||||
trait AccountControllerBase extends ControllerBase {
|
||||
self: SystemSettingsService with AccountService with RepositoryService with OneselfAuthenticator =>
|
||||
self: SystemSettingsService with AccountService with RepositoryService with ActivityService
|
||||
with OneselfAuthenticator =>
|
||||
|
||||
case class AccountNewForm(userName: String, password: String,mailAddress: String, url: Option[String])
|
||||
|
||||
@@ -33,8 +35,13 @@ trait AccountControllerBase extends ControllerBase {
|
||||
*/
|
||||
get("/:userName") {
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName).map {
|
||||
account.html.info(_, getVisibleRepositories(userName, baseUrl, context.loginAccount.map(_.userName)))
|
||||
getAccountByUserName(userName).map { x =>
|
||||
params.getOrElse("tab", "repositories") match {
|
||||
// Public Activity
|
||||
case "activity" => account.html.activity(x, getActivitiesByUser(userName, true))
|
||||
// Repositories
|
||||
case _ => account.html.repositories(x, getVisibleRepositories(userName, baseUrl, context.loginAccount.map(_.userName)))
|
||||
}
|
||||
} getOrElse NotFound
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,15 @@ import org.apache.commons.io._
|
||||
import jp.sf.amateras.scalatra.forms._
|
||||
|
||||
class CreateRepositoryController extends CreateRepositoryControllerBase
|
||||
with RepositoryService with AccountService with WikiService with LabelsService with UsersAuthenticator
|
||||
with RepositoryService with AccountService with WikiService with LabelsService with ActivityService
|
||||
with UsersAuthenticator
|
||||
|
||||
/**
|
||||
* Creates new repository.
|
||||
*/
|
||||
trait CreateRepositoryControllerBase extends ControllerBase {
|
||||
self: RepositoryService with WikiService with LabelsService with UsersAuthenticator =>
|
||||
self: RepositoryService with WikiService with LabelsService with ActivityService
|
||||
with UsersAuthenticator =>
|
||||
|
||||
case class RepositoryCreationForm(name: String, description: Option[String])
|
||||
|
||||
@@ -36,7 +38,8 @@ trait CreateRepositoryControllerBase extends ControllerBase {
|
||||
* Create new repository.
|
||||
*/
|
||||
post("/new", form)(usersOnly { form =>
|
||||
val loginUserName = context.loginAccount.get.userName
|
||||
val loginAccount = context.loginAccount.get
|
||||
val loginUserName = loginAccount.userName
|
||||
|
||||
// Insert to the database at first
|
||||
createRepository(form.name, loginUserName, form.description)
|
||||
@@ -82,7 +85,10 @@ trait CreateRepositoryControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
// Create Wiki repository
|
||||
createWikiRepository(context.loginAccount.get, form.name)
|
||||
createWikiRepository(loginAccount, form.name)
|
||||
|
||||
// Record activity
|
||||
recordCreateRepository(loginUserName, form.name, loginUserName)
|
||||
|
||||
// redirect to the repository
|
||||
redirect("/%s/%s".format(loginUserName, form.name))
|
||||
|
||||
21
src/main/scala/model/Activity.scala
Normal file
21
src/main/scala/model/Activity.scala
Normal file
@@ -0,0 +1,21 @@
|
||||
package model
|
||||
|
||||
import scala.slick.driver.H2Driver.simple._
|
||||
|
||||
object Activities extends Table[Activity]("ACTIVITY") with BasicTemplate with Functions {
|
||||
def activityId = column[Int]("ACTIVITY_ID", O AutoInc)
|
||||
def activityUserName = column[String]("ACTIVITY_USER_NAME")
|
||||
def message = column[String]("MESSAGE")
|
||||
def activityDate = column[java.util.Date]("ACTIVITY_DATE")
|
||||
def * = activityId ~ userName ~ repositoryName ~ activityUserName ~ message ~ activityDate <> (Activity, Activity.unapply _)
|
||||
def autoInc = userName ~ repositoryName ~ activityUserName ~ message ~ activityDate returning activityId
|
||||
}
|
||||
|
||||
case class Activity(
|
||||
activityId: Int,
|
||||
userName: String,
|
||||
repositoryName: String,
|
||||
activityUserName: String,
|
||||
message: String,
|
||||
activityDate: java.util.Date
|
||||
)
|
||||
30
src/main/scala/service/ActivityService.scala
Normal file
30
src/main/scala/service/ActivityService.scala
Normal file
@@ -0,0 +1,30 @@
|
||||
package service
|
||||
|
||||
import model._
|
||||
import Activities._
|
||||
import scala.slick.driver.H2Driver.simple._
|
||||
import Database.threadLocalSession
|
||||
|
||||
trait ActivityService {
|
||||
|
||||
def getActivitiesByUser(activityUserName: String, isPublic: Boolean): List[Activity] = {
|
||||
val q = Query(Activities)
|
||||
.innerJoin(Repositories).on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
|
||||
|
||||
(if(isPublic){
|
||||
q filter { case (t1, t2) => (t1.activityUserName is activityUserName.bind) && (t2.isPrivate is false.bind) }
|
||||
} else {
|
||||
q filter { case (t1, t2) => t1.activityUserName is activityUserName.bind }
|
||||
})
|
||||
.sortBy { case (t1, t2) => t1.activityId desc }
|
||||
.map { case (t1, t2) => t1 }
|
||||
.list
|
||||
}
|
||||
|
||||
def recordCreateRepository(userName: String, repositoryName: String, activityUserName: String): Unit = {
|
||||
Activities.autoInc insert(userName, repositoryName, activityUserName,
|
||||
"[[%s]] created [[%s/%s]]".format(activityUserName, userName, repositoryName),
|
||||
currentDate)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,8 +49,9 @@ object AutoUpdate {
|
||||
* The history of versions. A head of this sequence is the current BitBucket version.
|
||||
*/
|
||||
val versions = Seq(
|
||||
Version(1, 1),
|
||||
Version(1, 0)
|
||||
Version(1, 2),
|
||||
Version(1, 1),
|
||||
Version(1, 0)
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,13 @@ object helpers {
|
||||
Html(Markdown.toHtml(value, repository, enableWikiLink, enableCommitLink, enableIssueLink))
|
||||
}
|
||||
|
||||
def activityMessage(message: String)(implicit context: app.Context): Html = {
|
||||
Html(message
|
||||
.replaceAll("\\[\\[([^\\s]+?)/([^\\s]+?)\\]\\]", "<a href=\"%s/$1/$2\">$1/$2</a>".format(context.path))
|
||||
.replaceAll("\\[\\[([^\\s]+?)\\]\\]", "<a href=\"%s/$1\">$1</a>".format(context.path))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the url to the repository.
|
||||
*/
|
||||
@@ -61,6 +68,9 @@ object helpers {
|
||||
// convert commit id to link
|
||||
.replaceAll("(^|\\W)([a-f0-9]{40})(\\W|$)", "$1<a href=\"%s/%s/%s/commit/$2\">$2</a>$3").format(context.path, repository.owner, repository.name))
|
||||
|
||||
/**
|
||||
* Implicit conversion to add mkHtml() to Seq[Html].
|
||||
*/
|
||||
implicit def extendsHtmlSeq(seq: Seq[Html]) = new {
|
||||
def mkHtml(separator: String) = Html(seq.mkString(separator))
|
||||
def mkHtml(separator: scala.xml.Elem) = Html(seq.mkString(separator.toString))
|
||||
|
||||
31
src/main/twirl/account/activity.scala.html
Normal file
31
src/main/twirl/account/activity.scala.html
Normal file
@@ -0,0 +1,31 @@
|
||||
@(account: model.Account, activities: List[model.Activity])(implicit context: app.Context)
|
||||
@import context._
|
||||
@import view.helpers._
|
||||
@html.main(account.userName){
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="span4">
|
||||
<div class="block">
|
||||
<div class="block-header">@account.userName</div>
|
||||
</div>
|
||||
<div class="block">
|
||||
<div><i class="icon-home"></i> <a href="@account.url">@account.url</a></div>
|
||||
<div><i class="icon-time"></i> <span class="muted">Joined on</span> @date(account.registeredDate)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span8">
|
||||
@tab(account, "activity")
|
||||
@if(activities.isEmpty){
|
||||
No activity
|
||||
} else {
|
||||
@activities.map { activity =>
|
||||
<div class="block">
|
||||
<div class="muted small">@datetime(activity.activityDate)</div>
|
||||
<div>@activityMessage(activity.message)</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -14,19 +14,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="span8">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#">Repositories</a></li>
|
||||
<!--
|
||||
<li><a href="#">Activity</a></li>
|
||||
-->
|
||||
@if(loginAccount.isDefined && loginAccount.get.userName == account.userName){
|
||||
<li class="pull-right">
|
||||
<div class="button-group">
|
||||
<a href="@url(account.userName)/_edit" class="btn">Edit Your Profile</a>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
@tab(account, "repositories")
|
||||
@if(repositories.isEmpty){
|
||||
No repositories
|
||||
} else {
|
||||
14
src/main/twirl/account/tab.scala.html
Normal file
14
src/main/twirl/account/tab.scala.html
Normal file
@@ -0,0 +1,14 @@
|
||||
@(account: model.Account, active: String)(implicit context: app.Context)
|
||||
@import context._
|
||||
@import view.helpers._
|
||||
<ul class="nav nav-tabs">
|
||||
<li@if(active == "repositories"){ class="active"}><a href="@url(account.userName)?tab=repositories">Repositories</a></li>
|
||||
<li@if(active == "activity"){ class="active"}><a href="@url(account.userName)?tab=activity">Public Activity</a></li>
|
||||
@if(loginAccount.isDefined && loginAccount.get.userName == account.userName){
|
||||
<li class="pull-right">
|
||||
<div class="button-group">
|
||||
<a href="@url(account.userName)/_edit" class="btn">Edit Your Profile</a>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
Reference in New Issue
Block a user