working on configuration
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
.idea
|
.idea
|
||||||
target
|
target
|
||||||
|
config/config.json
|
||||||
|
*.sqlite3
|
||||||
|
|||||||
5
config/config.template.json
Normal file
5
config/config.template.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"port" : 80,
|
||||||
|
"base_dir" : "/home/srichter/workspace/Widerhall/static",
|
||||||
|
"base_url" : "http://localhost",
|
||||||
|
}
|
||||||
8
pom.xml
8
pom.xml
@@ -84,10 +84,8 @@
|
|||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.antlr</groupId>
|
<groupId>org.antlr</groupId>
|
||||||
<artifactId>stringtemplate</artifactId>
|
<artifactId>ST4</artifactId>
|
||||||
<version>4.0.2</version>
|
<version>4.3.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
</project>
|
||||||
</project>
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package de.srsoftware.widerhall;
|
|||||||
import de.srsoftware.widerhall.mail.Forwarder;
|
import de.srsoftware.widerhall.mail.Forwarder;
|
||||||
import de.srsoftware.widerhall.mail.ImapClient;
|
import de.srsoftware.widerhall.mail.ImapClient;
|
||||||
import de.srsoftware.widerhall.mail.MessageHandler;
|
import de.srsoftware.widerhall.mail.MessageHandler;
|
||||||
import de.srsoftware.widerhall.web.Static;
|
import de.srsoftware.widerhall.web.Web;
|
||||||
import de.srsoftware.widerhall.web.Rest;
|
import de.srsoftware.widerhall.web.Rest;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
@@ -11,18 +11,23 @@ import org.eclipse.jetty.server.ServerConnector;
|
|||||||
import org.eclipse.jetty.server.session.SessionHandler;
|
import org.eclipse.jetty.server.session.SessionHandler;
|
||||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
import java.io.File;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class Application {
|
public class Application {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Application.class);
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
var config = Configuration.setFile(new File("/tmp/config.json"));
|
var config = Configuration.instance();
|
||||||
|
// the following construct allows the initial config file to point to another config file, which is then loaded:
|
||||||
|
while (!config.configFile().equals(config.file())) config.load(config.configFile());
|
||||||
|
|
||||||
//startMailSystem(json);
|
//startMailSystem(json);
|
||||||
startWebserver(config);
|
startWebserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startWebserver(Configuration config) throws Exception {
|
private static void startWebserver() throws Exception {
|
||||||
|
var config = Configuration.instance();
|
||||||
var server = new Server();
|
var server = new Server();
|
||||||
var connector = new ServerConnector(server);
|
var connector = new ServerConnector(server);
|
||||||
connector.setPort(config.serverPort());
|
connector.setPort(config.serverPort());
|
||||||
@@ -31,7 +36,7 @@ public class Application {
|
|||||||
server.setConnectors(new Connector[]{connector});
|
server.setConnectors(new Connector[]{connector});
|
||||||
ServletContextHandler context = new ServletContextHandler(server, "/",sh,null,null,null);
|
ServletContextHandler context = new ServletContextHandler(server, "/",sh,null,null,null);
|
||||||
context.addServlet(Rest.class,"/api");
|
context.addServlet(Rest.class,"/api");
|
||||||
context.addServlet(Static.class,"/static/*");
|
context.addServlet(Web.class,"/web/*");
|
||||||
|
|
||||||
server.start();
|
server.start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,50 +3,87 @@ package de.srsoftware.widerhall;
|
|||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
import org.json.simple.parser.JSONParser;
|
import org.json.simple.parser.JSONParser;
|
||||||
import org.json.simple.parser.ParseException;
|
import org.json.simple.parser.ParseException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
|
||||||
import static de.srsoftware.widerhall.Constants.*;
|
import static de.srsoftware.widerhall.Constants.*;
|
||||||
public class Configuration {
|
public class Configuration {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Configuration.class);
|
||||||
private static Configuration singleton = null;
|
private static Configuration singleton = null;
|
||||||
private JSONObject data;
|
private JSONObject data;
|
||||||
private final File file;
|
private File file;
|
||||||
|
|
||||||
public Configuration(File configFile) throws IOException, ParseException {
|
|
||||||
this.file = configFile;
|
|
||||||
if (!configFile.exists()){
|
|
||||||
setDefaults();
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
var content = Files.readString(configFile.toPath());
|
|
||||||
data = (JSONObject) new JSONParser().parse(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Configuration setFile(File file) throws IOException, ParseException {
|
|
||||||
singleton = new Configuration(file);
|
|
||||||
return singleton;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Configuration instance() {
|
public static Configuration instance() {
|
||||||
|
if (singleton == null) singleton = new Configuration().setDefaults();
|
||||||
return singleton;
|
return singleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDefaults() throws MalformedURLException {
|
/**
|
||||||
if (data == null) data = new JSONObject();
|
* Merges configuration from file into current configuration.
|
||||||
baseDir();
|
* Existing entries will be replaced.
|
||||||
serverPort();
|
* @param file
|
||||||
tokenUrl();
|
* @return
|
||||||
loginUrl();
|
* @throws IOException
|
||||||
baseUrl();
|
* @throws ParseException
|
||||||
clientId();
|
*/
|
||||||
clientSecret();
|
public Configuration load(File file) {
|
||||||
|
this.file = file;
|
||||||
|
if (file.exists()) try {
|
||||||
|
var newVals = (JSONObject) new JSONParser().parse(Files.readString(file.toPath()));
|
||||||
|
data.putAll(newVals);
|
||||||
|
} catch (ParseException | IOException e){
|
||||||
|
LOG.warn("Was not able to load configuration from {}:",file,e);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void save() throws IOException {
|
public Configuration save(File file) throws IOException {
|
||||||
|
this.file = file;
|
||||||
|
return save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Configuration save() throws IOException {
|
||||||
|
if (file == null) throw new NullPointerException("Cannot save configuration: file is null!");
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
Files.writeString(file.toPath(),data.toJSONString());
|
Files.writeString(file.toPath(),data.toJSONString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration setDefaults() {
|
||||||
|
if (data == null) data = new JSONObject();
|
||||||
|
configFile();
|
||||||
|
dbFile();
|
||||||
|
baseUrl();
|
||||||
|
serverPort();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject locations() {
|
||||||
|
Object o = data.get(LOCATIONS);
|
||||||
|
if (!(o instanceof JSONObject)) data.put(LOCATIONS,o = new JSONObject());
|
||||||
|
return (JSONObject) o;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String baseDir() {
|
||||||
|
var locations = locations();
|
||||||
|
if (!locations.containsKey(BASE)) locations.put(BASE,System.getProperty("user.dir"));
|
||||||
|
return (String) locations.get(BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File configFile() {
|
||||||
|
var locations = locations();
|
||||||
|
if (!locations.containsKey(CONFIG)) locations.put(CONFIG, String.join(File.separator,baseDir(),"config","config.json"));
|
||||||
|
return new File((String) locations.get(CONFIG));
|
||||||
|
}
|
||||||
|
|
||||||
|
public File dbFile() {
|
||||||
|
var locations = locations();
|
||||||
|
if (!locations.containsKey(DB)) locations.put(DB, String.join(File.separator,baseDir(),"db","db.sqlite3"));
|
||||||
|
return new File((String) locations.get(DB));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int serverPort() {
|
public int serverPort() {
|
||||||
@@ -55,38 +92,13 @@ public class Configuration {
|
|||||||
return (int) (long) o;
|
return (int) (long) o;
|
||||||
}
|
}
|
||||||
|
|
||||||
public URL tokenUrl() throws MalformedURLException {
|
|
||||||
if (!data.containsKey(TOKEN_URL)) data.put(TOKEN_URL,"http://localhost:"+serverPort()+"/oauth/token");
|
|
||||||
return new URL((String) data.get(TOKEN_URL));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String loginUrl() {
|
|
||||||
if (!data.containsKey(LOGIN_URL)) data.put(LOGIN_URL,"http://localhost:"+serverPort()+"/oauth/login");
|
|
||||||
return (String) data.get(LOGIN_URL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String baseUrl() {
|
public String baseUrl() {
|
||||||
if (!data.containsKey(BASE_URL)) data.put(BASE_URL,"http://localhost");
|
if (!data.containsKey(BASE_URL)) data.put(BASE_URL,"http://localhost");
|
||||||
return (String) data.get(BASE_URL);
|
return (String) data.get(BASE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String clientId() {
|
|
||||||
if (!data.containsKey(CLIENT_ID)) data.put(CLIENT_ID,"widerhall");
|
|
||||||
return (String) data.get(CLIENT_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clientSecret() {
|
public File file() {
|
||||||
if (!data.containsKey(CLIENT_SECRET)) data.put(CLIENT_SECRET,"changeme");
|
return file;
|
||||||
return (String) data.get(CLIENT_SECRET);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String dbLocation() {
|
|
||||||
if (!data.containsKey(DB_FILE)) data.put(DB_FILE,System.getProperty("user.home")+"/.config/widerhall/db.sqlite3");
|
|
||||||
return (String) data.get(DB_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String baseDir() {
|
|
||||||
if (!data.containsKey(Constants.BASE_DIR)) data.put(BASE_DIR,System.getProperty("user.dir")+"/static");
|
|
||||||
return (String) data.get(BASE_DIR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ public class Constants {
|
|||||||
public static final String BASE_URL = "base_url";
|
public static final String BASE_URL = "base_url";
|
||||||
public static final String CLIENT_ID = "client_id";
|
public static final String CLIENT_ID = "client_id";
|
||||||
public static final String CLIENT_SECRET = "client_secret";
|
public static final String CLIENT_SECRET = "client_secret";
|
||||||
public static final String DB_FILE = "db_file";
|
public static final String DB = "database";
|
||||||
public static final String BASE_DIR = "base_dir";
|
public static final String BASE = "base";
|
||||||
|
public static final String CONFIG = "configuration";
|
||||||
|
public static final String LOCATIONS = "locations";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,10 +127,10 @@ public class Database {
|
|||||||
public static Database open() {
|
public static Database open() {
|
||||||
if (singleton == null){
|
if (singleton == null){
|
||||||
Configuration config = Configuration.instance();
|
Configuration config = Configuration.instance();
|
||||||
String dbFile = config.dbLocation();
|
var dbFile = config.dbFile();
|
||||||
String url = "jdbc:sqlite:"+dbFile;
|
String url = "jdbc:sqlite:"+dbFile;
|
||||||
LOG.debug("Opening {}",url);
|
LOG.debug("Opening {}",url);
|
||||||
new File(dbFile).getParentFile().mkdirs();
|
dbFile.getParentFile().mkdirs();
|
||||||
try {
|
try {
|
||||||
singleton = new Database(DriverManager.getConnection(url)).assertTables();
|
singleton = new Database(DriverManager.getConnection(url)).assertTables();
|
||||||
} catch (SQLException sqle) {
|
} catch (SQLException sqle) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import de.srsoftware.widerhall.data.User;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.stringtemplate.v4.STGroup;
|
import org.stringtemplate.v4.STGroup;
|
||||||
import org.stringtemplate.v4.STGroupDir;
|
import org.stringtemplate.v4.STRawGroupDir;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
@@ -19,17 +19,19 @@ import java.util.Map;
|
|||||||
|
|
||||||
import static de.srsoftware.widerhall.Util.t;
|
import static de.srsoftware.widerhall.Util.t;
|
||||||
|
|
||||||
public class Static extends HttpServlet {
|
public class Web extends HttpServlet {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Static.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Web.class);
|
||||||
|
private static final String LOGIN = "login";
|
||||||
private final String baseDir;
|
private final String baseDir;
|
||||||
private final STGroup templates;
|
private final STGroup templates;
|
||||||
|
private static final String WEB_ROOT = "/web";
|
||||||
|
|
||||||
public Static(){
|
public Web(){
|
||||||
var config = Configuration.instance();
|
var config = Configuration.instance();
|
||||||
baseDir = config.baseDir();
|
baseDir = config.baseDir();
|
||||||
var templateDir = String.join(File.separator,baseDir,"templates");
|
var templateDir = String.join(File.separator,baseDir,"static","templates");
|
||||||
templates = new STGroupDir(templateDir,'{','}');
|
templates = new STRawGroupDir(templateDir,'«','»');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -43,13 +45,11 @@ public class Static extends HttpServlet {
|
|||||||
path = path == null ? "index" : path.substring(1);
|
path = path == null ? "index" : path.substring(1);
|
||||||
switch (path){
|
switch (path){
|
||||||
case "css":
|
case "css":
|
||||||
return loadFile("style.css",resp);
|
|
||||||
case "js":
|
case "js":
|
||||||
return loadFile("widerhall.js",resp);
|
case "login":
|
||||||
|
return loadTemplate(path,null,resp);
|
||||||
case "jquery":
|
case "jquery":
|
||||||
return loadFile("jquery-3.6.0.min.js",resp);
|
return loadFile("jquery-3.6.0.min.js",resp);
|
||||||
case "login":
|
|
||||||
return loadTemplate(path, null, resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var u = req.getSession().getAttribute("user");
|
var u = req.getSession().getAttribute("user");
|
||||||
@@ -77,7 +77,7 @@ public class Static extends HttpServlet {
|
|||||||
|
|
||||||
private String loginRedirect(HttpServletResponse resp) {
|
private String loginRedirect(HttpServletResponse resp) {
|
||||||
try {
|
try {
|
||||||
resp.sendRedirect("/static/login");
|
resp.sendRedirect(String.join("/",WEB_ROOT,LOGIN));
|
||||||
return null;
|
return null;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return t("Was not able to redirect to login page: {}", e.getMessage());
|
return t("Was not able to redirect to login page: {}", e.getMessage());
|
||||||
@@ -123,7 +123,7 @@ public class Static extends HttpServlet {
|
|||||||
try {
|
try {
|
||||||
var user = User.load(email,pass);
|
var user = User.load(email,pass);
|
||||||
req.getSession().setAttribute("user",user);
|
req.getSession().setAttribute("user",user);
|
||||||
resp.sendRedirect("/static");
|
resp.sendRedirect(String.join("/",WEB_ROOT,"index"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
try {
|
try {
|
||||||
LOG.warn("Static.handleLogin failed:",e);
|
LOG.warn("Static.handleLogin failed:",e);
|
||||||
23
static/templates/css.st
Normal file
23
static/templates/css.st
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login form {
|
||||||
|
width: 450px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error{
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
background: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user{
|
||||||
|
background: lime;
|
||||||
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
index(data) ::= <<
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<script src="static/jquery"></script>
|
<script src="jquery"></script>
|
||||||
<script src="static/js"></script>
|
<script src="js"></script>
|
||||||
|
<link rel="stylesheet" href="css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<span class="user">Logged in as <em>{data.user.name}</em></span>
|
<span class="user">Logged in as <em>«data.user.name»</em></span>
|
||||||
<h2>Users</h2>
|
<h2>Users</h2>
|
||||||
<h2>Lists</h2>
|
<h2>Lists</h2>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
>>
|
|
||||||
@@ -1,30 +1,28 @@
|
|||||||
login(data) ::= <<
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<script src="/static/jquery"></script>
|
<script src="jquery"></script>
|
||||||
<script src="/static/js"></script>
|
<script src="js"></script>
|
||||||
<link rel="stylesheet" href="/static/css" />
|
<link rel="stylesheet" href="css" />
|
||||||
</head>
|
</head>
|
||||||
<body id="login">
|
<body id="login">
|
||||||
<h1>Widerhall login</h1>
|
<h1>Widerhall login</h1>
|
||||||
{if(data.error)}
|
«if(data.error)»
|
||||||
<span class="error">{data.error}</span>
|
<span class="error">«data.error»</span>
|
||||||
{endif}
|
«endif»
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Login-Daten</legend>
|
<legend>Login-Daten</legend>
|
||||||
<label>
|
<label>
|
||||||
<input type="text" name="email" value="" id="email" />
|
<input type="text" name="email" value="" id="email" />
|
||||||
E-Mail-Adresse
|
E-Mail-Adresse
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<input type="password" name="pass" value="" id="password" />
|
<input type="password" name="pass" value="" id="password" />
|
||||||
Passwort
|
Passwort
|
||||||
</label>
|
</label>
|
||||||
<button type="submit">Einloggen</button>
|
<button type="submit">Einloggen</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
>>
|
|
||||||
Reference in New Issue
Block a user