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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties

#dotenv
src/main/resources/.env
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
# OfficeHours
A web-based system to manage office hours

### Known Issues
1. [Failed to compile with Scala 2.13](https://github.com/UB-CSE/OfficeHours/issues/174)

### Contribution Guide

#### 1. How to Build this Project
1. Set up Scala SDK
2. Mark `src/main/scala` as `Source Root` if need
3. Set up the local configurations
- Rename `src/main/resources/.env.example` to `src/main/resources/.env`

Revise anything you need to change (Ex: change DB configurations. By default, it will
use `List` as DB Driver, that means you don't really need to care about the DB connection
if you're not familiar with it, but data(Ex: Queue data), will lose once you restart the project).

4. Build it.
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@
</plugin>

</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>

<targetPath>src/main/resources/.env</targetPath>
</resource>
</resources>
</build>

</project>
24 changes: 24 additions & 0 deletions src/main/resources/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# src/main/resources/.env.example
# Rename this file into `.env`
# to make this project work

# ENV
#
# Not used by anything yet
ENV=DEV

# DB_TYPE
# Type of the database the server gonna use
# Types are implemented in model.database,
# Loaded in src/main/scala/model/Configuration
#
# "MySQL" || "List"
# Default: "List"
DB_TYPE=List

# DB Connection Informations
# Only need if you're using MySQL as

# DB_URL=jdbc:mysql://localhost/officehours?autoReconnect=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
# DB_USERNAME=root
# DB_PASSWORD=root
51 changes: 51 additions & 0 deletions src/main/scala/helper/dotenv/DirtyEnvironmentHack.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package helper.dotenv

import java.util.Collections
import scala.util.control.NonFatal
import scala.util.{Failure, Success, Try}

/**
* Rewrite the runtime Environment, embedding entries from the .env file.
*
* Taken from: https://github.com/mefellows/sbt-dotenv/blob/master/src/main/scala/au/com/onegeek/sbtdotenv/DirtyEnvironmentHack.scala
* Original from: http://stackoverflow.com/questions/318239/how-do-i-set-environment-variables-from-java/7201825#7201825
*
* Created by mfellows on 20/07/2014.
*/
object DirtyEnvironmentHack {
def setEnv(newEnv: java.util.Map[String, String]): Unit = {
Try({
val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")

val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
theEnvironmentField.setAccessible(true)
val env = theEnvironmentField.get(null).asInstanceOf[java.util.Map[String, String]] // scalastyle:off null
env.putAll(newEnv)

val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
theCaseInsensitiveEnvironmentField.setAccessible(true)
val ciEnv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[java.util.Map[String, String]] // scalastyle:off null
ciEnv.putAll(newEnv)
}) match {
case Failure(_: NoSuchFieldException) =>
Try({
val classes = classOf[Collections].getDeclaredClasses
val env = System.getenv
classes.filter(_.getName == "java.util.Collections$UnmodifiableMap").foreach(cl => {
val field = cl.getDeclaredField("m")
field.setAccessible(true)
val map = field.get(env).asInstanceOf[java.util.Map[String, String]]
map.clear()
map.putAll(newEnv)
})
}) match {
case Failure(NonFatal(e2)) =>
e2.printStackTrace()
case Success(_) =>
}
case Failure(NonFatal(e1)) =>
e1.printStackTrace()
case Success(_) =>
}
}
}
36 changes: 36 additions & 0 deletions src/main/scala/helper/dotenv/Dotenv.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package helper.dotenv

import scala.io.Source
import scala.util.{Failure, Success, Try}
import collection.JavaConverters._

object Dotenv {
// To load .env file to the Environmental Variables for development
def loadEnv(envFilePath: String = ".env"): Unit = {
var envLines: List[String] = Try(Source.fromResource(envFilePath).getLines().toList) match {
case Success(lines) => lines
case Failure(e) => {
print("[Warn] Failed to load .env: ")
println(e)

// return empty list if .env not exist
List()
}
}

for (line <- envLines) {
// skip the lines which are commented out
if (line.trim != "" && !line.trim.startsWith("#")) {
// Split the line by character `=` once
var lineContent: Array[String] = line.split("=", 2)
if (lineContent.length > 0) {
if (lineContent.length == 2) {
DirtyEnvironmentHack.setEnv((sys.env ++ Map(
lineContent(0) -> lineContent(1)
)).asJava)
}
}
}
}
}
}
17 changes: 17 additions & 0 deletions src/main/scala/model/Configuration.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
package model

import scala.util.{Failure, Success, Try}

object Configuration {

val DEV_MODE = true

/**
* DB_TYPE
*
* Type of the database the server gonna use
* Types are implemented in model.database
*
* "MySQL" || "List"
*
* default: "List"
* */
var DB_TYPE: String = Try(sys.env("DB_TYPE")) match {
case Success(dbType) => dbType
case Failure(e) => "List"
}

}
16 changes: 11 additions & 5 deletions src/main/scala/model/OfficeHoursServer.scala
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
package model

import model.{Configuration => LocalConfiguration}
import com.corundumstudio.socketio.listener.{DataListener, DisconnectListener}
import com.corundumstudio.socketio.{AckRequest, Configuration, SocketIOClient, SocketIOServer}
import com.corundumstudio.socketio.{AckRequest, SocketIOClient, SocketIOServer, Configuration => SocketIOConfiguration}
import helper.dotenv.Dotenv
import model.database.{Database, DatabaseAPI, TestingDatabase}
import play.api.libs.json.{JsValue, Json}


class OfficeHoursServer() {

val database: DatabaseAPI = if(Configuration.DEV_MODE){
new TestingDatabase
}else{
val database: DatabaseAPI = if(LocalConfiguration.DB_TYPE == "MySQL") {
new Database
} else {
// fallback to using List as DB if it's "List" or others
new TestingDatabase
}

var usernameToSocket: Map[String, SocketIOClient] = Map()
var socketToUsername: Map[SocketIOClient, String] = Map()

val config: Configuration = new Configuration {
val config: SocketIOConfiguration = new SocketIOConfiguration {
setHostname("0.0.0.0")
setPort(8080)
}
Expand All @@ -40,6 +43,9 @@ class OfficeHoursServer() {

object OfficeHoursServer {
def main(args: Array[String]): Unit = {
// Load environmental variables
Dotenv.loadEnv()

new OfficeHoursServer()
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/model/database/Database.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import model.StudentInQueue

class Database extends DatabaseAPI{

val url = "jdbc:mysql://mysql/officehours?autoReconnect=true"
val url: String = sys.env("DB_URL")
val username: String = sys.env("DB_USERNAME")
val password: String = sys.env("DB_PASSWORD")

Expand Down