Skip to content

Commit 4ab6335

Browse files
committed
Deploying to gh-pages from @ scala-text/scala_text@50425af 🚀
1 parent cabbd9d commit 4ab6335

File tree

82 files changed

+22165
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+22165
-0
lines changed

lockfileVersion/IDE.html

Lines changed: 629 additions & 0 deletions
Large diffs are not rendered by default.

lockfileVersion/advanced-trait-di.html

Lines changed: 950 additions & 0 deletions
Large diffs are not rendered by default.

lockfileVersion/basic.html

Lines changed: 739 additions & 0 deletions
Large diffs are not rendered by default.

lockfileVersion/case-class-and-pattern-matching.html

Lines changed: 913 additions & 0 deletions
Large diffs are not rendered by default.

lockfileVersion/class.html

Lines changed: 796 additions & 0 deletions
Large diffs are not rendered by default.

lockfileVersion/collection.html

Lines changed: 1120 additions & 0 deletions
Large diffs are not rendered by default.

lockfileVersion/control-syntax.html

Lines changed: 1004 additions & 0 deletions
Large diffs are not rendered by default.

lockfileVersion/error-handling.html

Lines changed: 1196 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
scalaVersion := "2.13.15"
2+
3+
crossScalaVersions += "3.6.2"
4+
5+
libraryDependencies ++= Seq(
6+
"org.scalikejdbc" %% "scalikejdbc" % "4.3.2",
7+
"org.mindrot" % "jbcrypt" % "0.4"
8+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sbt.version=1.10.7
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package domain
2+
3+
case class User(id: Long, name: String, hashedPassword: String)
4+
5+
object User {
6+
def apply(name: String, hashedPassword: String): User =
7+
User(0L, name, hashedPassword)
8+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package domain
2+
3+
import org.mindrot.jbcrypt.BCrypt
4+
import scalikejdbc._
5+
6+
class UserService {
7+
val maxNameLength = 32
8+
9+
// ストレージ機能
10+
def insert(user: User): User = DB localTx { implicit s =>
11+
val id = sql"""insert into users (name, password) values (${user.name}, ${user.hashedPassword})"""
12+
.updateAndReturnGeneratedKey.apply()
13+
user.copy(id = id)
14+
}
15+
16+
def createUser(rs: WrappedResultSet): User =
17+
User(rs.long("id"), rs.string("name"), rs.string("password"))
18+
19+
def find(name: String): Option[User] = DB readOnly { implicit s =>
20+
sql"""select * from users where name = $name """
21+
.map(createUser).single.apply()
22+
}
23+
24+
def find(id: Long): Option[User] = DB readOnly { implicit s =>
25+
sql"""select * from users where id = $id """
26+
.map(createUser).single.apply()
27+
}
28+
29+
// パスワード機能
30+
def hashPassword(rawPassword: String): String =
31+
BCrypt.hashpw(rawPassword, BCrypt.gensalt())
32+
33+
def checkPassword(rawPassword: String, hashedPassword: String): Boolean =
34+
BCrypt.checkpw(rawPassword, hashedPassword)
35+
36+
// ユーザー登録
37+
def register(name: String, rawPassword: String): User = {
38+
if (name.length > maxNameLength) {
39+
throw new Exception("Too long name!")
40+
}
41+
if (find(name).isDefined) {
42+
throw new Exception("Already registered!")
43+
}
44+
insert(User(name, hashPassword(rawPassword)))
45+
}
46+
47+
// ユーザー認証
48+
def login(name: String, rawPassword: String): User = {
49+
find(name) match {
50+
case None => throw new Exception("User not found!")
51+
case Some(user) =>
52+
if (!checkPassword(rawPassword, user.hashedPassword)) {
53+
throw new Exception("Invalid password!")
54+
}
55+
user
56+
}
57+
}
58+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
scalaVersion := "2.13.15"
2+
3+
crossScalaVersions += "3.6.2"
4+
5+
libraryDependencies ++= Seq(
6+
"org.scalikejdbc" %% "scalikejdbc" % "4.3.2",
7+
"org.mindrot" % "jbcrypt" % "0.4",
8+
"org.scalatest" %% "scalatest-wordspec" % "3.2.19" % "test"
9+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sbt.version=1.10.7
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package domain
2+
3+
import org.mindrot.jbcrypt.BCrypt
4+
5+
trait PasswordService {
6+
def hashPassword(rawPassword: String): String
7+
8+
def checkPassword(rawPassword: String, hashedPassword: String): Boolean
9+
}
10+
11+
trait PasswordServiceImpl extends PasswordService {
12+
def hashPassword(rawPassword: String): String =
13+
BCrypt.hashpw(rawPassword, BCrypt.gensalt())
14+
15+
def checkPassword(rawPassword: String, hashedPassword: String): Boolean =
16+
BCrypt.checkpw(rawPassword, hashedPassword)
17+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package domain
2+
3+
case class User(id: Long, name: String, hashedPassword: String)
4+
5+
object User {
6+
def apply(name: String, hashedPassword: String): User =
7+
User(0L, name, hashedPassword)
8+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package domain
2+
3+
import scalikejdbc._
4+
5+
trait UserRepository {
6+
def insert(user: User): User
7+
8+
def find(name: String): Option[User]
9+
10+
def find(id: Long): Option[User]
11+
}
12+
13+
trait UserRepositoryImpl extends UserRepository {
14+
def insert(user: User): User = DB localTx { implicit s =>
15+
val id = sql"""insert into users (name, password) values (${user.name}, ${user.hashedPassword})"""
16+
.updateAndReturnGeneratedKey.apply()
17+
user.copy(id = id)
18+
}
19+
20+
def createUser(rs: WrappedResultSet): User =
21+
User(rs.long("id"), rs.string("name"), rs.string("password"))
22+
23+
def find(name: String): Option[User] = DB readOnly { implicit s =>
24+
sql"""select * from users where name = $name """
25+
.map(createUser).single.apply()
26+
}
27+
28+
def find(id: Long): Option[User] = DB readOnly { implicit s =>
29+
sql"""select * from users where id = $id """
30+
.map(createUser).single.apply()
31+
}
32+
}
33+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package domain
2+
3+
trait UserService {
4+
self: PasswordService with UserRepository =>
5+
6+
val maxNameLength = 32
7+
8+
def register(name: String, rawPassword: String): User = {
9+
if (name.length > maxNameLength) {
10+
throw new Exception("Too long name!")
11+
}
12+
if (find(name).isDefined) {
13+
throw new Exception("Already registered!")
14+
}
15+
insert(User(name, hashPassword(rawPassword)))
16+
}
17+
18+
def login(name: String, rawPassword: String): User = {
19+
find(name) match {
20+
case None => throw new Exception("User not found!")
21+
case Some(user) =>
22+
if (!checkPassword(rawPassword, user.hashedPassword)) {
23+
throw new Exception("Invalid password!")
24+
}
25+
user
26+
}
27+
}
28+
}
29+
30+
class UserServiceImpl extends UserService with PasswordServiceImpl with UserRepositoryImpl
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package domain
2+
3+
import org.scalatest._
4+
import org.scalatest.wordspec.AnyWordSpec
5+
6+
class UserServiceSpec extends AnyWordSpec {
7+
val user = User(1, "test_name", "test_password")
8+
9+
val sut = new UserService with PasswordServiceImpl with UserRepository {
10+
def find(id: Long): Option[domain.User] = Some(user)
11+
def find(name: String): Option[domain.User] = Some(user)
12+
def insert(user: domain.User): domain.User = user
13+
}
14+
15+
"register" should {
16+
"throw an exception if a name is too long" in {
17+
val exception = intercept[Exception] {
18+
sut.register("too long name" * 100, "password")
19+
}
20+
assert(exception.getMessage === "Too long name!")
21+
}
22+
23+
"throw an exception if a name is already registered" in {
24+
val exception = intercept[Exception] {
25+
sut.register("test_name", "password")
26+
}
27+
assert(exception.getMessage === "Already registered!")
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)