This repository has been archived by the owner on Apr 27, 2023. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
37 changed files
with
878 additions
and
18 deletions.
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
codebrag-dao/src/main/resources/db/migration/V19__add_teams.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
CREATE TABLE IF NOT EXISTS "teams"( | ||
"id" VARCHAR NOT NULL, | ||
"name" VARCHAR NOT NULL, | ||
); | ||
ALTER TABLE "teams" ADD CONSTRAINT IF NOT EXISTS "pk" PRIMARY KEY("id"); | ||
|
||
CREATE TABLE IF NOT EXISTS "team_members"( | ||
"team_id" VARCHAR NOT NULL, | ||
"user_id" VARCHAR NOT NULL, | ||
"contributor" BOOLEAN NOT NULL | ||
); | ||
ALTER TABLE "team_members" ADD CONSTRAINT IF NOT EXISTS "pk" PRIMARY KEY("team_id", "user_id"); | ||
|
||
ALTER TABLE "team_members" ADD CONSTRAINT IF NOT EXISTS "team_id" FOREIGN KEY ("team_id") REFERENCES "teams" ("id") ON DELETE CASCADE ON UPDATE CASCADE NOCHECK; | ||
ALTER TABLE "team_members" ADD CONSTRAINT IF NOT EXISTS "user_id" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE NOCHECK; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
codebrag-dao/src/main/scala/com/softwaremill/codebrag/dao/teams/SQLTeamDAO.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package com.softwaremill.codebrag.dao.user | ||
|
||
import com.softwaremill.codebrag.dao.sql.SQLDatabase | ||
import com.softwaremill.codebrag.domain._ | ||
import org.bson.types.ObjectId | ||
import org.joda.time.{ DateTime, DateTimeZone } | ||
|
||
class SQLTeamDAO(val database: SQLDatabase) extends TeamDAO with SQLTeamSchema { | ||
import database._ | ||
import database.driver.simple._ | ||
|
||
def add(team: Team) { | ||
db.withTransaction { implicit session => | ||
teams += new TeamTuple(team.id, team.name) | ||
} | ||
} | ||
|
||
def countAll() = { | ||
db.withTransaction { implicit session => | ||
Query(teams.length).first().toLong | ||
} | ||
} | ||
|
||
def findAll() = db.withTransaction { implicit session => | ||
teams.list().map(queryTeamMembers).map(untuple) | ||
} | ||
|
||
def findById(teamId: ObjectId) = db.withTransaction { implicit session => | ||
val q = for { | ||
t <- teams if (t.id === teamId) | ||
} yield (t) | ||
|
||
q.firstOption.map(queryTeamMembers).map(untuple) | ||
} | ||
|
||
def findByName(name: String) = db.withTransaction { implicit session => | ||
val q = for { | ||
t <- teams if (t.name === name) | ||
} yield (t) | ||
|
||
q.firstOption.map(queryTeamMembers).map(untuple) | ||
} | ||
|
||
def findByUser(userId: ObjectId) = db.withTransaction { implicit session => | ||
teamMembers.where(_.userId === userId).list().map(t => findById(t.team_id).get); | ||
} | ||
|
||
def modifyTeam(team: Team) = db.withTransaction { implicit session => | ||
teams.where(_.id === team.id).update(tuple(team)) | ||
|
||
// Remove members from database. | ||
teamMembers.where(_.teamId === team.id).delete | ||
|
||
// Insert new ones | ||
teamMembers.insertAll(team.teamMembers.map(t => SQLTeamMember(team.id, t.user_id, t.contributor)).toSeq: _*) | ||
} | ||
|
||
def delete(teamId: ObjectId) = db.withTransaction { implicit session => | ||
teams.where(_.id === teamId).delete | ||
|
||
teamMembers.where(_.teamId === teamId).delete | ||
} | ||
|
||
private def queryTeamMembers(tuple: TeamTuple)(implicit session: Session) = { | ||
val teamId = tuple._1 | ||
val members = teamMembers.where(_.teamId === teamId).list() | ||
(tuple, members) | ||
} | ||
|
||
} |
52 changes: 52 additions & 0 deletions
52
codebrag-dao/src/main/scala/com/softwaremill/codebrag/dao/teams/SQLTeamSchema.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.softwaremill.codebrag.dao.user | ||
|
||
import com.softwaremill.codebrag.dao.sql.SQLDatabase | ||
import com.softwaremill.codebrag.domain._ | ||
import org.bson.types.ObjectId | ||
import org.joda.time.DateTime | ||
import scala.slick.model.ForeignKeyAction | ||
|
||
trait SQLTeamSchema { | ||
val database: SQLDatabase | ||
|
||
import database._ | ||
import database.driver.simple._ | ||
|
||
protected case class SQLTeamMember(team_id: ObjectId, user_id: ObjectId, contributor: Boolean = true) { | ||
def toTeamMember = TeamMember(team_id, user_id, contributor) | ||
} | ||
|
||
protected val teamMembers = TableQuery[TeamMembers] | ||
|
||
protected class Teams(tag: Tag) extends Table[TeamTuple](tag, "teams") { | ||
def id = column[ObjectId]("id", O.PrimaryKey) | ||
def name = column[String]("name") | ||
|
||
def teammembers = foreignKey("team_members_fk", id, teamMembers)(_.teamId, ForeignKeyAction.Cascade, ForeignKeyAction.Cascade) | ||
|
||
def * = (id, name) | ||
} | ||
|
||
protected class TeamMembers(tag: Tag) extends Table[SQLTeamMember](tag, "team_members") { | ||
def teamId = column[ObjectId]("team_id") | ||
def userId = column[ObjectId]("user_id") | ||
def contributor = column[Boolean]("contributor") | ||
|
||
def * = (teamId, userId, contributor) <> (SQLTeamMember.tupled, SQLTeamMember.unapply) | ||
} | ||
|
||
protected val teams = TableQuery[Teams] | ||
|
||
protected type TeamTuple = (ObjectId, String) | ||
|
||
protected def tuple(team: Team): TeamTuple = (team.id, team.name) | ||
|
||
protected val untuple: ((TeamTuple, List[SQLTeamMember])) => Team = { | ||
case (tuple, sqlTeamMembers) => | ||
Team( | ||
tuple._1, | ||
tuple._2, | ||
sqlTeamMembers.map(_.toTeamMember).toList) | ||
} | ||
|
||
} |
23 changes: 23 additions & 0 deletions
23
codebrag-dao/src/main/scala/com/softwaremill/codebrag/dao/teams/TeamDAO.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.softwaremill.codebrag.dao.user | ||
|
||
import com.softwaremill.codebrag.domain._ | ||
import org.joda.time.DateTime | ||
import org.bson.types.ObjectId | ||
|
||
trait TeamDAO { | ||
def add(team: Team) | ||
|
||
def findAll(): List[Team] | ||
|
||
def findById(teamId: ObjectId): Option[Team] | ||
|
||
def findByName(name: String): Option[Team] | ||
|
||
def findByUser(userId: ObjectId): List[Team] | ||
|
||
def modifyTeam(team: Team) | ||
|
||
def delete(teamId: ObjectId) | ||
|
||
def countAll(): Long | ||
} |
10 changes: 10 additions & 0 deletions
10
codebrag-domain/src/main/scala/com/softwaremill/codebrag/domain/Team.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.softwaremill.codebrag.domain | ||
|
||
import com.softwaremill.codebrag.common.Utils | ||
import org.bson.types.ObjectId | ||
|
||
case class Team(id: ObjectId, name: String, teamMembers: List[TeamMember] = null) | ||
|
||
case class TeamMember(team_id: ObjectId, user_id: ObjectId, contributor: Boolean = true) { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
codebrag-rest/src/main/scala/com/softwaremill/codebrag/rest/TeamsServlet.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package com.softwaremill.codebrag.rest | ||
|
||
import com.softwaremill.codebrag.service.user.{ RegisterService, Authenticator } | ||
import com.softwaremill.codebrag.service.config.CodebragConfig | ||
import org.bson.types.ObjectId | ||
import org.scalatra | ||
import com.softwaremill.codebrag.usecases.team.{ AddTeamUseCase, DeleteTeamUseCase, AddTeamMemberUseCase, DeleteTeamMemberUseCase, ModifyTeamMemberUseCase } | ||
import com.softwaremill.codebrag.finders.team.TeamFinder | ||
import com.softwaremill.codebrag.finders.team.ManagedTeamMembersListView | ||
|
||
class TeamsServlet( | ||
val authenticator: Authenticator, | ||
teamFinder: TeamFinder, | ||
addTeamUseCase: AddTeamUseCase, | ||
deleteTeamUseCase: DeleteTeamUseCase, | ||
addTeamMemberUseCase: AddTeamMemberUseCase, | ||
deleteTeamMemberUseCase: DeleteTeamMemberUseCase, | ||
modifyTeamMemberUseCase: ModifyTeamMemberUseCase, | ||
config: CodebragConfig) extends JsonServletWithAuthentication { | ||
|
||
get("/") { | ||
haltIfNotAuthenticated() | ||
teamFinder.findAllTeams() | ||
} | ||
|
||
post("/") { | ||
haltIfNotAuthenticated() | ||
val teamName = extractReq[String]("name") | ||
addTeamUseCase.execute(new ObjectId, teamName) match { | ||
case Left(errors) => scalatra.BadRequest(errors) | ||
case Right(teamCreated) => scalatra.Ok(teamCreated) | ||
} | ||
} | ||
|
||
delete("/:teamId") { | ||
haltIfNotAuthenticated() | ||
val teamIdToRemove = new ObjectId(params("teamId")) | ||
deleteTeamUseCase.execute(teamIdToRemove) match { | ||
case Left(errors) => scalatra.BadRequest(errors) | ||
case _ => scalatra.Ok() | ||
} | ||
} | ||
|
||
get("/:teamId/members") { | ||
haltIfNotAuthenticated() | ||
if (!config.demo) { | ||
var team = teamFinder.findTeam(new ObjectId(params("teamId"))); | ||
teamFinder.findAllAsManagedTeamMembers(team) | ||
} else { | ||
ManagedTeamMembersListView(List.empty) | ||
} | ||
} | ||
|
||
post("/:teamId/members") { | ||
haltIfNotAuthenticated() | ||
val targetTeamId = new ObjectId(extractOpt[String]("teamId").get) | ||
val targetUserId = new ObjectId(extractOpt[String]("userId").get) | ||
addTeamMemberUseCase.execute(targetTeamId, targetUserId) match { | ||
case Left(errors) => scalatra.BadRequest(errors) | ||
case Right(team) => scalatra.Ok(team) | ||
} | ||
} | ||
|
||
delete("/:teamId/members/:userId") { | ||
haltIfNotAuthenticated() | ||
val targetTeamId = new ObjectId(params("teamId")) | ||
val targetUserId = new ObjectId(params("userId")) | ||
deleteTeamMemberUseCase.execute(targetTeamId, targetUserId) match { | ||
case Left(errors) => scalatra.BadRequest(errors) | ||
case Right(team) => scalatra.Ok(team) | ||
} | ||
} | ||
|
||
put("/:teamId/members") { | ||
haltIfNotAuthenticated() | ||
val targetTeamId = new ObjectId(extractOpt[String]("teamId").get) | ||
val targetUserId = new ObjectId(extractOpt[String]("userId").get) | ||
val contributorOpt = extractOpt[Boolean]("contributor") | ||
modifyTeamMemberUseCase.execute(targetTeamId, targetUserId, contributorOpt) match { | ||
case Left(errors) => scalatra.BadRequest(errors) | ||
case Right(team) => scalatra.Ok(team) | ||
} | ||
} | ||
|
||
object TeamsServlet { | ||
val MappingPath = "teams" | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
...g-service/src/main/scala/com/softwaremill/codebrag/finders/commits/TeamMemberLoader.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.softwaremill.codebrag.finders.commits | ||
|
||
import org.bson.types.ObjectId | ||
import com.softwaremill.codebrag.dao.user.{UserDAO, TeamDAO} | ||
import com.typesafe.scalalogging.slf4j.Logging | ||
|
||
protected[finders] trait TeamMemberLoader extends Logging { | ||
|
||
protected def userDao: UserDAO | ||
|
||
protected def teamDao: TeamDAO | ||
|
||
protected def loadTeamMembersWithDetails(userId: ObjectId) = userDao.findPartialUserDetails(loadTeamMembers(userId)).toList | ||
|
||
protected def loadTeamMembers(userId: ObjectId) = teamDao.findByUser(userId).flatMap(_.teamMembers).filter(_.contributor).map(_.user_id).distinct.toList | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.