Allow exporting all data in bson, json, or csv formats.

This commit is contained in:
MarkBryanMilligan
2022-01-29 18:25:19 -06:00
parent eeec6cc697
commit eaf1e4504f
117 changed files with 41205 additions and 10527 deletions
@@ -6,7 +6,7 @@ import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubCommands;
import com.lanternsoftware.rules.RulesEngine;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import javax.servlet.ServletContextEvent;
@@ -24,7 +24,7 @@ public class Globals implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
RulesEngine.instance().start();
RulesEngine.instance().schedule(new CommandTask(), 0);
}
@@ -1,17 +1,10 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.currentmonitor.util.GoogleAuthHelper;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.servlet.BasicAuth;
import com.lanternsoftware.util.servlet.LanternServlet;
import org.slf4j.Logger;
@@ -23,15 +16,7 @@ import javax.servlet.http.HttpServletResponse;
@WebServlet("/auth/*")
public class AuthServlet extends LanternServlet {
private static final NetHttpTransport transport = new NetHttpTransport();
private static final Logger logger = LoggerFactory.getLogger(AuthServlet.class);
private static final String googleClientId;
private static final String googleClientSecret;
static {
DaoEntity google = DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.OPS_PATH + "google_sso.txt"));
googleClientId = DaoSerializer.getString(google, "id");
googleClientSecret = DaoSerializer.getString(google, "secret");
}
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
@@ -40,16 +25,7 @@ public class AuthServlet extends LanternServlet {
BasicAuth auth = new BasicAuth(_req);
if (NullUtils.isEqual(auth.getUsername(), "googlesso")) {
logger.info("Attempting google SSO");
try {
GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(transport, new GsonFactory(), "https://oauth2.googleapis.com/token", googleClientId, googleClientSecret, auth.getPassword(), "").execute();
if (tokenResponse != null) {
GoogleIdToken idToken = tokenResponse.parseIdToken();
if (idToken != null)
authCode = Globals.dao.getAuthCodeForEmail(idToken.getPayload().getEmail(), DateUtils.fromTimeZoneId(_req.getHeader("timezone")));
}
} catch (Exception _e) {
logger.error("Failed to validate google auth code", _e);
}
authCode = GoogleAuthHelper.signin(auth.getPassword(), DateUtils.fromTimeZoneId(_req.getHeader("timezone")));
} else
authCode = Globals.dao.authenticateAccount(auth.getUsername(), auth.getPassword());
}
@@ -14,7 +14,7 @@ import javax.ws.rs.core.MediaType;
import java.util.Date;
@WebServlet("/charge/*")
public class ChargeServlet extends SecureServlet {
public class ChargeServlet extends SecureServiceServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
@@ -7,7 +7,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/command")
public class CommandServlet extends SecureServlet {
public class CommandServlet extends SecureServiceServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
@@ -13,7 +13,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/config/*")
public class ConfigServlet extends SecureServlet {
public class ConfigServlet extends SecureServiceServlet {
private static final Logger logger = LoggerFactory.getLogger(ConfigServlet.class);
@Override
@@ -14,7 +14,7 @@ import javax.ws.rs.core.MediaType;
import java.util.Date;
@WebServlet("/energy/*")
public class EnergyServlet extends SecureServlet {
public class EnergyServlet extends SecureServiceServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
@@ -0,0 +1,23 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.util.servlet.FreemarkerConfigUtil;
import com.lanternsoftware.util.servlet.FreemarkerServlet;
import com.lanternsoftware.util.servlet.FreemarkerUtil;
import freemarker.template.Configuration;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public abstract class FreemarkerCMServlet extends FreemarkerServlet {
protected static final Configuration CONFIG = FreemarkerConfigUtil.createConfig(FreemarkerCMServlet.class, "/templates", 100);
@Override
protected Configuration getFreemarkerConfig() {
return CONFIG;
}
public void renderBody(HttpServletResponse _rep, String _sHtmlResourceKey, Map<String, Object> _mapModel) {
_mapModel.put("body", FreemarkerUtil.render(getFreemarkerConfig(), _sHtmlResourceKey, _mapModel));
render(_rep, "frame.ftl", _mapModel);
}
}
@@ -9,7 +9,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/generateBom")
public class GenerateBomServlet extends SecureServlet {
public class GenerateBomServlet extends SecureServiceServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode authCode = Globals.dao.decryptAuthCode(_req.getHeader("auth_code"));
@@ -15,7 +15,7 @@ import javax.ws.rs.core.MediaType;
import java.util.*;
@WebServlet("/energy/group/*")
public class GroupEnergyServlet extends SecureServlet {
public class GroupEnergyServlet extends SecureServiceServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
@@ -10,7 +10,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/power/group/*")
public class GroupPowerServlet extends SecureServlet {
public class GroupPowerServlet extends SecureServiceServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
@@ -19,7 +19,7 @@ import javax.servlet.http.HttpServletResponse;
import java.util.List;
@WebServlet("/power/*")
public class PowerServlet extends SecureServlet {
public class PowerServlet extends SecureServiceServlet {
private static final Logger logger = LoggerFactory.getLogger(MongoCurrentMonitorDao.class);
@Override
@@ -3,7 +3,6 @@ package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
@@ -12,7 +11,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/rebuildSummaries/*")
public class RebuildSummariesServlet extends SecureServlet {
public class RebuildSummariesServlet extends SecureServiceServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
if (_authCode.getAccountId() == 100) {
@@ -1,7 +1,8 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
@@ -30,7 +31,7 @@ import java.io.IOException;
public class ResetPasswordServlet extends FreemarkerServlet {
protected static final Logger LOG = LoggerFactory.getLogger(ResetPasswordServlet.class);
protected static final Configuration CONFIG = FreemarkerConfigUtil.createConfig(ResetPasswordServlet.class, "/templates", 100);
protected static final String api_key = ResourceLoader.loadFileAsString(LanternFiles.OPS_PATH + "sendgrid.txt");
protected static final String api_key = ResourceLoader.loadFileAsString(LanternFiles.CONFIG_PATH + "sendgrid.txt");
@Override
protected Configuration getFreemarkerConfig() {
@@ -40,7 +41,7 @@ public class ResetPasswordServlet extends FreemarkerServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _resp) {
String[] path = getPath(_req);
String email = Globals.dao.getEmailForResetKey(path[1]);
String email = Globals.dao.getEmailForResetKey(CollectionUtils.get(path, 1));
if (EmailValidator.getInstance().isValid(email)) {
render(_resp, "passwordReset.ftl", model(_req, "key", path[1]));
} else {
@@ -7,7 +7,7 @@ import com.lanternsoftware.util.servlet.LanternServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class SecureServlet extends LanternServlet {
public abstract class SecureServiceServlet extends LanternServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode authCode = Globals.dao.decryptAuthCode(_req.getHeader("auth_code"));
@@ -1,6 +1,6 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.servlet.LanternServlet;
@@ -16,8 +16,8 @@ public class UpdateServlet extends LanternServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
if (isPath(_req, 0, "version"))
setResponseEntity(_rep, MediaType.APPLICATION_OCTET_STREAM, DaoSerializer.toZipBson(DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.OPS_PATH + "release" + File.separator + "version.json"))));
setResponseEntity(_rep, MediaType.APPLICATION_OCTET_STREAM, DaoSerializer.toZipBson(DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.CONFIG_PATH + "release" + File.separator + "version.json"))));
else
setResponseEntity(_rep, MediaType.APPLICATION_OCTET_STREAM, ResourceLoader.loadFile(LanternFiles.OPS_PATH + "release" + File.separator + "lantern-currentmonitor.jar"));
setResponseEntity(_rep, MediaType.APPLICATION_OCTET_STREAM, ResourceLoader.loadFile(LanternFiles.CONFIG_PATH + "release" + File.separator + "lantern-currentmonitor.jar"));
}
}
@@ -0,0 +1,19 @@
package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.util.dao.auth.AuthCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("")
public class ConsoleServlet extends SecureConsoleServlet {
private static final Logger logger = LoggerFactory.getLogger(ConsoleServlet.class);
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
redirect(_rep, "export");
}
}
@@ -0,0 +1,140 @@
package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.archive.ArchiveStatus;
import com.lanternsoftware.datamodel.currentmonitor.archive.BreakerEnergyArchive;
import com.lanternsoftware.datamodel.currentmonitor.archive.DailyEnergyArchive;
import com.lanternsoftware.datamodel.currentmonitor.archive.MonthlyEnergyArchive;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
import org.apache.commons.io.IOUtils;
import org.bson.codecs.DocumentCodec;
import org.bson.codecs.EncoderContext;
import org.bson.json.JsonWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.zip.Deflater;
import java.util.zip.GZIPOutputStream;
@WebServlet("/export/*")
public class ExportServlet extends SecureConsoleServlet {
private static final Logger logger = LoggerFactory.getLogger(ExportServlet.class);
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
TimeZone tz = Globals.dao.getTimeZoneForAccount(_authCode.getAccountId());
String[] path = path(_req);
if (path.length > 1) {
synchronized (this) {
InputStream is = Globals.dao.streamArchive(_authCode.getAccountId(), new Date(DaoSerializer.toLong(path[0])));
if (is == null) {
redirect(_rep, _req.getContextPath() + "/export");
return;
}
OutputStream os = null;
GZIPOutputStream gout = null;
JsonWriter jsonWriter = null;
try {
os = _rep.getOutputStream();
if (NullUtils.makeNotNull(path[1]).contains("csv")) {
BreakerConfig config = Globals.dao.getConfig(_authCode.getAccountId()); //TODO: get historical config for this month in case it's changed since then.
Map<Integer, Breaker> breakers = CollectionUtils.transformToMap(config.getAllBreakers(), Breaker::getIntKey);
os = new GZIPOutputStream(os) {{def.setLevel(Deflater.BEST_SPEED);}};
MonthlyEnergyArchive archive = DaoSerializer.fromZipBson(IOUtils.toByteArray(is), MonthlyEnergyArchive.class);
DailyEnergyArchive fday = CollectionUtils.getFirst(archive.getDays());
if (fday == null) {
redirect(_rep, _req.getContextPath() + "/export");
return;
}
StringBuilder header = new StringBuilder("Timestamp");
for (BreakerEnergyArchive ba : CollectionUtils.makeNotNull(fday.getBreakers())) {
Breaker b = breakers.get(Breaker.intKey(ba.getPanel(), ba.getSpace()));
header.append(",");
if (b != null) {
header.append(b.getKey());
header.append("-");
header.append(b.getName());
}
}
header.append("\n");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
os.write(NullUtils.toByteArray(header.toString()));
Date dayStart = archive.getMonth();
for (DailyEnergyArchive day : CollectionUtils.makeNotNull(archive.getDays())) {
Date dayEnd = DateUtils.addDays(dayStart, 1, tz);
int secondsInDay = (int) ((dayEnd.getTime() - dayStart.getTime()) / 1000);
for (int sec = 0; sec < secondsInDay; sec++) {
StringBuilder line = new StringBuilder();
line.append(df.format(new Date(dayStart.getTime() + ((long) sec * 1000))));
for (BreakerEnergyArchive b : CollectionUtils.makeNotNull(day.getBreakers())) {
line.append(",");
if ((b.getReadings() == null) || (sec * 4 >= b.getReadings().length))
line.append("NaN");
else {
ByteBuffer readings = ByteBuffer.wrap(b.getReadings());
line.append(readings.getFloat(sec * 4));
}
}
line.append("\n");
os.write(NullUtils.toByteArray(line.toString()));
}
}
return;
}
if (NullUtils.makeNotNull(path[1]).contains("json")) {
DaoEntity archive = DaoSerializer.fromZipBson(IOUtils.toByteArray(is));
gout = new GZIPOutputStream(os) {{def.setLevel(Deflater.BEST_SPEED);}};
jsonWriter = new JsonWriter(new OutputStreamWriter(gout, StandardCharsets.UTF_8), DaoSerializer.JSON_COMPACT_SETTINGS);
new DocumentCodec().encode(jsonWriter, archive.toDocument(), EncoderContext.builder().build());
return;
}
IOUtils.copy(is, os);
return;
} catch (Exception _e) {
logger.error("Failed to send archive to browser", _e);
redirect(_rep, _req.getContextPath() + "/export");
return;
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(jsonWriter);
IOUtils.closeQuietly(gout);
IOUtils.closeQuietly(os);
}
}
}
List<ArchiveStatus> status = Globals.dao.getArchiveStatus(_authCode.getAccountId());
List<MonthDisplay> months = CollectionUtils.transform(status, _s->new MonthDisplay(DateUtils.format("MMMM yyyy", tz, _s.getMonth()), _s.getMonth().getTime(), (int)_s.getProgress()));
Map<String, Object> model = model(_req, "months", months);
model.put("inprogress", CollectionUtils.anyQualify(months, _m->_m.getProgress() > 0 && _m.getProgress() < 100));
renderBody(_rep, "export.ftl", model);
}
@Override
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
Date month = new Date(DaoSerializer.toLong(_req.getParameter("month")));
Globals.dao.archiveMonth(_authCode.getAccountId(), month);
redirect(_rep, ".");
}
}
@@ -0,0 +1,33 @@
package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
import com.lanternsoftware.currentmonitor.util.GoogleAuthHelper;
import com.lanternsoftware.util.NullUtils;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/gso")
public class GsoServlet extends FreemarkerCMServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
render(_rep, "login.ftl", model(_req));
}
@Override
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
String code = getRequestPayloadAsString(_req);
if (NullUtils.isNotEmpty(code)) {
String authCode = GoogleAuthHelper.signin(code, null);
if (NullUtils.isNotEmpty(authCode)) {
Cookie authCookie = new Cookie("auth_code", authCode);
authCookie.setMaxAge(157680000);
authCookie.setSecure(true);
_rep.addCookie(authCookie);
_req.getSession().setAttribute("auth_code", authCode);
}
}
}
}
@@ -0,0 +1,42 @@
package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
import com.lanternsoftware.currentmonitor.util.GoogleAuthHelper;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
import com.lanternsoftware.util.servlet.LanternServlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends FreemarkerCMServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
render(_rep, "login.ftl", model(_req));
}
@Override
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
String username = _req.getParameter("username");
String password = _req.getParameter("password");
String authCode = Globals.dao.authenticateAccount(username, password);
if (NullUtils.isNotEmpty(authCode)) {
Cookie authCookie = new Cookie("auth_code", authCode);
authCookie.setMaxAge(157680000);
authCookie.setSecure(true);
_rep.addCookie(authCookie);
_req.getSession().setAttribute("auth_code", authCode);
redirect(_rep, _req.getContextPath());
}
render(_rep, "login.ftl", model(_req, "error", "Invalid Credentials"));
}
}
@@ -0,0 +1,27 @@
package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
import com.lanternsoftware.currentmonitor.util.GoogleAuthHelper;
import com.lanternsoftware.util.NullUtils;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/logout")
public class LogoutServlet extends FreemarkerCMServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
_req.getSession().removeAttribute("auth_code");
Cookie authCookie = new Cookie("auth_code", "");
authCookie.setMaxAge(0);
authCookie.setSecure(true);
_rep.addCookie(authCookie);
redirect(_rep, _req.getContextPath());
}
@Override
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
}
}
@@ -0,0 +1,29 @@
package com.lanternsoftware.currentmonitor.servlet.console;
public class MonthDisplay {
public final String name;
public final long date;
public final int progress;
public MonthDisplay(String _name, long _date, int _progress) {
name = _name;
date = _date;
progress = _progress;
}
public String getName() {
return name;
}
public String getFileName() {
return name.replace(" ", "-");
}
public String getDate() {
return String.valueOf(date);
}
public int getProgress() {
return progress;
}
}
@@ -0,0 +1,48 @@
package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class SecureConsoleServlet extends FreemarkerCMServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode code = getAuthCode(_req, _rep);
if (code != null)
get(code, _req, _rep);
}
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
}
@Override
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode code = getAuthCode(_req, _rep);
if (code != null)
post(code, _req, _rep);
}
private AuthCode getAuthCode(HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode authCode = Globals.dao.decryptAuthCode(DaoSerializer.toString(_req.getSession().getAttribute("auth_code")));
if (authCode == null) {
Cookie authCookie = CollectionUtils.filterOne(CollectionUtils.asArrayList(_req.getCookies()), _c-> NullUtils.isEqual(_c.getName(), "auth_code"));
if (authCookie != null)
authCode = Globals.dao.decryptAuthCode(authCookie.getValue());
}
if (authCode == null) {
redirect(_rep, _req.getContextPath() + "/login");
return null;
}
return authCode;
}
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
}
}
@@ -0,0 +1,42 @@
package com.lanternsoftware.currentmonitor.util;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.TimeZone;
public class GoogleAuthHelper {
private static final Logger logger = LoggerFactory.getLogger(GoogleAuthHelper.class);
private static final NetHttpTransport transport = new NetHttpTransport();
private static final String googleClientId;
private static final String googleClientSecret;
static {
DaoEntity google = DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.CONFIG_PATH + "google_sso.txt"));
googleClientId = DaoSerializer.getString(google, "id");
googleClientSecret = DaoSerializer.getString(google, "secret");
}
public static String signin(String _code, TimeZone _tz) {
try {
GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(transport, new GsonFactory(), "https://oauth2.googleapis.com/token", googleClientId, googleClientSecret, _code, "postmessage").execute();
if (tokenResponse != null) {
GoogleIdToken idToken = tokenResponse.parseIdToken();
if (idToken != null)
return Globals.dao.getAuthCodeForEmail(idToken.getPayload().getEmail(), _tz);
}
} catch (Exception _e) {
logger.error("Failed to validate google auth code", _e);
}
return null;
}
}
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<#if inprogress><meta http-equiv="refresh" content="1"></#if>
<title>Lantern Console</title>
<link href="${link_prefix}/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="${link_prefix}bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid login-container">
<div class="row">
<div class="col-1 col-lg-3 col-4k-4"></div>
<div class="col-10 col-lg-6 col-4k-4">
<div class="row mt-3">
<table class="table">
<tbody>
<#list months as month>
<#if month.progress == 0>
<form method="POST">
</#if>
<tr>
<td>${month.name!}</td>
<#if month.progress == 0>
<td><input type="hidden" name="month" value="${month.date}"/><input type="submit" class="btn-primary border-none px-2 py-1" value="Export"/></td>
<#elseif month.progress == 1>
<td>Queued</td>
<#elseif month.progress < 100>
<td>Progress ${month.progress!}%</td>
<#else>
<td>
<a href="export/${month.date}/${month.fileName!}.bson.zip" class="btn-primary border-none text-decoration-none p-2" download>BSON</a>
<a href="export/${month.date}/${month.fileName!}.json.zip" class="btn-primary border-none text-decoration-none p-2" download>JSON</a>
<a href="export/${month.date}/${month.fileName!}.csv.zip" class="btn-primary border-none text-decoration-none p-2" download>CSV</a>
</td>
</#if>
</tr>
<#if month.progress == 0>
</form>
</#if>
</#list>
</tbody>
</table>
</div>
<div class="col-1 col-lg-3 col-4k-4"></div>
</div>
</body>
</html>
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Lantern Power Monitor</title>
<link rel="icon" type="image/png" href="${link_prefix}img/favicon.png">
<link href="${link_prefix}bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="${link_prefix}bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
<main>
<div class="container-fluid">
<div class="row header-menu py-2">
<div class="col-2"></div>
<div class="col-auto"><img class="img-fluid" alt="Logo" src="${link_prefix}img/logo_40.png"/></div>
<div class="col"></div>
<div class="col-auto mx-2"><a href="${link_prefix}" class="text-decoration-none header-link fmnu1">DATA EXPORT</a></div>
<div class="col-auto mx-2"><a href="${link_prefix}logout" class="text-decoration-none header-link fmnu1">LOGOUT</a></div>
<div class="col-2"></div>
</div>
<div class="row">
<div class="col-12">
${body}
</div>
</div>
</div>
</main>
</body>
</html>
@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
<script>
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({client_id: '412929846491-r3uh0t67mpeouicjvlara580i9cfchol.apps.googleusercontent.com', cookie_policy: 'none', redirect_uri: 'postmessage'});
});
}
</script>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Lantern Power Monitor</title>
<link rel="icon" type="image/png" href="${link_prefix}img/favicon.png">
<link href="${link_prefix}bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="${link_prefix}bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
<main>
<div class="container-fluid login-container">
<form method="POST">
<div class="row">
<div class="col-1 col-lg-3 col-4k-4"></div>
<div class="col-10 col-lg-6 col-4k-4">
<div class="row pt-5">
<div class="col-12">
<img class="img-fluid" alt='Lantern Logo' src='${link_prefix}img/lantern_cm.png'/>
</div>
</div>
<div class="row pt-5">
<div class="col-1 col-lg-2"></div>
<div class="col-10 col-lg-8">
<input type="email" name="username" class="login-input" placeholder="email"/>
</div>
<div class="col-1 col-lg-2"></div>
</div>
<div class="row pt-2">
<div class="col-1 col-lg-2"></div>
<div class="col-10 col-lg-8">
<input type="password" name="password" class="login-input" placeholder="password"/>
</div>
<div class="col-1 col-lg-2"></div>
</div>
<div class="row pt-2">
<div class="col-1 col-lg-2"></div>
<div class="col-8 col-lg-6 d-flex"><button type="button" id="signinButton" class="gso"></button></div>
<div class="col-2 d-flex justify-content-end">
<input type="submit" class="btn-primary border-none px-3" value="Login"/>
</div>
<div class="col-1 col-lg-2"></div>
</div>
<div class="row pt-5">
<div class="col-1 col-lg-2"></div>
<div class="col-10 col-lg-8 error">
${error!}
</div>
<div class="col-1 col-lg-2"></div>
</div>
</div>
<div class="col-1 col-lg-3 col-4k-4"></div>
</div>
</form>
</div>
<div class="login-bkgnd"></div>
<script>
$('#signinButton').click(function() {
auth2.grantOfflineAccess().then(signInCallback);
});
function signInCallback(authResult) {
if (authResult['code']) {
$.ajax({
type: 'POST',
url: 'gso',
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
window.location.replace('./');
},
processData: false,
data: authResult['code']
});
} else {
// There was an error.
}
}
</script>
</main>
</body>
</html>
@@ -15,7 +15,7 @@
<div class="navy-line"></div>
<h4><img class="mr-1" src="${context}/img/logo_40.png">Reset Password</h4>
<form class="ml-2" method="POST">
<input type="hidden" name="reset_key" value="${key}"/>
<input type="hidden" name="reset_key" value="${key!}"/>
<div>New Password:</div>
<input type="password" name="password"/>
<input type="submit" class="btn-primary" value="Submit"/>
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,51 +1,150 @@
/*!
* Bootstrap Reboot v4.5.0 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors
* Copyright 2011-2020 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Bootstrap Reboot v5.1.1 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-bg: #fff;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus:not(:focus-visible) {
outline: 0 !important;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
h1, h2, h3, h4, h5, h6 {
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
@@ -54,12 +153,10 @@ p {
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
@@ -70,6 +167,11 @@ address {
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
@@ -89,7 +191,7 @@ dt {
}
dd {
margin-bottom: .5rem;
margin-bottom: 0.5rem;
margin-left: 0;
}
@@ -103,42 +205,39 @@ strong {
}
small {
font-size: 80%;
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 75%;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
bottom: -0.25em;
}
sup {
top: -.5em;
top: -0.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
}
a:hover {
color: #0056b3;
color: #0d6efd;
text-decoration: underline;
}
a:not([href]) {
color: inherit;
text-decoration: none;
a:hover {
color: #0a58ca;
}
a:not([href]):hover {
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
@@ -147,59 +246,94 @@ pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-family: var(--bs-font-monospace);
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
img,
svg {
overflow: hidden;
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
margin-bottom: 0.5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
button:focus:not(:focus-visible) {
outline: 0;
}
input,
@@ -213,54 +347,45 @@ textarea {
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
[role="button"] {
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type="button"]:not(:disabled),
[type="reset"]:not(:disabled),
[type="submit"]:not(:disabled) {
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
textarea {
overflow: auto;
resize: vertical;
}
@@ -272,33 +397,59 @@ fieldset {
}
legend {
display: block;
float: left;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
color: inherit;
white-space: normal;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
progress {
vertical-align: baseline;
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
::-webkit-inner-spin-button {
height: auto;
}
[type="search"] {
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
@@ -310,16 +461,21 @@ output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,478 @@
/*!
* Bootstrap Reboot v5.1.1 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-bg: #fff;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,229 @@
.scrollarea {
overflow-y: auto;
}
.fw-semibold { font-weight: 600; }
.lh-tight { line-height: 1.25; }
.menu_link {
text-decoration:none!important;
}
.menu_subitem {
color:#404040;
}
.menu_item, .menu_subitem:hover, .menu_subitem:focus {
background-color: #1a9acc;
color:#f0f0f0;
}
.lpm_menu {
z-index:1;
background:#ffffff;
min-height:100%;
max-height:100%;
}
#toggle_label {
margin-top:0.5rem;
display: block;
width: 2rem;
position:absolute;
z-index: 10;
}
.blue, .title {
color: #1a9acc;
}
.kill {
color: #ff0000;
}
.max-w-300 {
max-width:min(100%,300px);
}
.max-w-400 {
max-width:min(100%,400px);
}
.max-w-500 {
max-width:min(100%,500px);
}
.max-w-600 {
max-width:min(100%,600px);
}
.max-w-700 {
max-width:min(100%,700px);
}
.max-w-800 {
max-width:min(100%,800px);
}
.max-w-900 {
max-width:min(100%,900px);
}
.max-w-1000 {
max-width:min(100%,1000px);
}
.max-w-1200 {
max-width:min(100%,1200px);
}
.align-col-right {
display: flex !important;
justify-content: flex-end !important;
padding-right: 1vw !important;
}
.align-col-left {
display: flex !important;
justify-content: flex-start !important;
padding-left: 1vw !important;
}
.title {
font-size: 2em;
}
.sub-title {
font-size: 1.1em;
}
@media (max-width: 991px) {
#menu_toggle:checked ~ #toggle_label {
position:fixed!important;
}
.lpm_menu {
display:none!important;
}
#menu_toggle:checked ~ .lpm_menu {
display:block!important;
}
#menu_toggle:checked ~ .lpm_body {
display: block!important;
width: 50%;
}
}
@media (min-width: 992px) {
.hsy {
margin-top: 2.3rem !important;
}
}
@media (min-width: 3000px) {
#menu_toggle:checked ~ .lpm_menu {
display:block!important;
}
#menu_toggle:checked ~ .lpm_body {
display: block!important;
width: 50%;
}
}
.fm1 {
font-size: calc(1rem + 1.25vw);
}
.fm2 {
font-size: calc(0.7rem + 1vw);
}
.fm3 {
font-size: calc(0.8rem + 0.5vw);
}
.fmnu1 {
font-size: calc(1rem + 0.5vw);
}
.fmnu2 {
font-size: calc(0.8rem + 0.5vw);
}
.login-container {
z-index:2;
position:absolute;
}
.login-bkgnd {
z-index:1;
position:absolute;
width: 100%;
height: 100%;
top:0;
left:0;
background-image:url('../../img/pcb.png');
background-size:cover;
background-position: center;
}
.login-input {
width: 100%;
}
::placeholder {
color: #a0a0a0;
opacity: 1;
}
.btn-primary {
background-color: #1a9acc;
border-color: #1a9acc;
}
.btn-primary:hover, .btn-primary:focus{
background-color: #20c0ff;
border-color: #20c0ff;
}
.header-menu {
background-color: #1a9acc;
}
.header-link {
color: #f0f0f0;
}
.header-link:hover {
color: #d0d0d0;
}
.gso {
border-style: none;
width: 10rem;
height: 2.5rem;
background-image: url("../../img/gso.png");
background-position: center;
background-size: cover;
background-color: #0000;
}
.gso:hover {
background-color: #0000;
}
.gso:focus {
background-image: url("../../img/gso_pressed.png");
}
.border-none {
border-style: none;
}
.error {
color: darkred;
}
@@ -0,0 +1 @@
.scrollarea{overflow-y:auto}.fw-semibold{font-weight:600}.lh-tight{line-height:1.25}.menu_link{text-decoration:none!important}.menu_subitem{color:#404040}.menu_item,.menu_subitem:focus,.menu_subitem:hover{background-color:#1a9acc;color:#f0f0f0}.lpm_menu{z-index:1;background:#fff;min-height:100%;max-height:100%}#toggle_label{margin-top:.5rem;display:block;width:2rem;position:absolute;z-index:10}.blue,.title{color:#1a9acc}.kill{color:red}.max-w-300{max-width:min(100%,300px)}.max-w-400{max-width:min(100%,400px)}.max-w-500{max-width:min(100%,500px)}.max-w-600{max-width:min(100%,600px)}.max-w-700{max-width:min(100%,700px)}.max-w-800{max-width:min(100%,800px)}.max-w-900{max-width:min(100%,900px)}.max-w-1000{max-width:min(100%,1000px)}.max-w-1200{max-width:min(100%,1200px)}.align-col-right{display:flex!important;justify-content:flex-end!important;padding-right:1vw!important}.align-col-left{display:flex!important;justify-content:flex-start!important;padding-left:1vw!important}.title{font-size:2em}.sub-title{font-size:1.1em}@media (max-width:991px){#menu_toggle:checked~#toggle_label{position:fixed!important}.lpm_menu{display:none!important}#menu_toggle:checked~.lpm_menu{display:block!important}#menu_toggle:checked~.lpm_body{display:block!important;width:50%}}@media (min-width:992px){.hsy{margin-top:2.3rem!important}}@media (min-width:3000px){#menu_toggle:checked~.lpm_menu{display:block!important}#menu_toggle:checked~.lpm_body{display:block!important;width:50%}}.fm1{font-size:calc(1rem + 1.25vw)}.fm2{font-size:calc(.7rem + 1vw)}.fm3{font-size:calc(.8rem + .5vw)}.fmnu1{font-size:calc(1rem + .5vw)}.fmnu2{font-size:calc(.8rem + .5vw)}.login-bkgnd,.login-container{z-index:2;position:absolute}.login-bkgnd{z-index:1;width:100%;height:100%;top:0;left:0;background-image:url(../../img/pcb.png);background-size:cover;background-position:center}.login-input{width:100%}::placeholder{color:#a0a0a0;opacity:1}.btn-primary{background-color:#1a9acc;border-color:#1a9acc}.btn-primary:focus,.btn-primary:hover{background-color:#20c0ff;border-color:#20c0ff}.header-menu{background-color:#1a9acc}.header-link{color:#f0f0f0}.header-link:hover{color:#d0d0d0}.gso{border-style:none;width:10rem;height:2.5rem;background-image:url(../../img/gso.png);background-position:center;background-size:cover}.gso,.gso:hover{background-color:#0000}.gso:focus{background-image:url(../../img/gso_pressed.png)}.border-none{border-style:none}.error{color:#8b0000}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

@@ -3,14 +3,12 @@ package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import java.util.Arrays;
public class CreateAccount {
public static void main(String[] args) {
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
Account account = new Account();
account.setId(1);
account.setPassword("*redacted*");
@@ -1,13 +1,13 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.cryptography.AESTool;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
public class CreateAuthCode {
private static final AESTool aes = new AESTool(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "authKey.dat"));
private static final AESTool aes = new AESTool(ResourceLoader.loadFile(LanternFiles.CONFIG_PATH + "authKey.dat"));
public static void main(String[] args) {
System.out.println(aes.encryptToBase64(DaoSerializer.toZipBson(new AuthCode(100, null))));
@@ -1,11 +1,11 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.cryptography.AESTool;
public class CreateAuthKey {
public static void main(String[] args) {
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "authKey.dat", AESTool.generateRandomSecretKey().getEncoded());
ResourceLoader.writeFile(LanternFiles.CONFIG_PATH + "authKey.dat", AESTool.generateRandomSecretKey().getEncoded());
}
}
@@ -4,26 +4,14 @@ import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPanel;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPolarity;
import com.lanternsoftware.datamodel.currentmonitor.Meter;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.IFilter;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class CreateBreakers {
public static void main(String[] args) {
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
/* Breaker bf1 = new Breaker("Solar A", 2, 20, 0, 1, 50, 1.6);
bf1.setPolarity(BreakerPolarity.SOLAR);
@@ -212,7 +200,6 @@ public class CreateBreakers {
Map<Integer, Integer> panelToMeter = CollectionUtils.transformToMap(config.getPanels(), BreakerPanel::getIndex, BreakerPanel::getMeter);
CollectionUtils.edit(config.getAllBreakers(), _b->_b.setMeter(DaoSerializer.toInteger(panelToMeter.get(_b.getPanel()))));*/
BreakerConfig config = dao.getConfig(1);
// BreakerConfig config = DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.OPS_PATH + "breakerconfig_backup_210107.json"), BreakerConfig.class);
// ResourceLoader.writeFile(LanternFiles.OPS_PATH + "breakerconfig_backup_210107.json", DaoSerializer.toJson(config));
// CollectionUtils.edit(config.getAllBreakerGroups(), _g->{
@@ -235,6 +222,34 @@ public class CreateBreakers {
// group.setId(String.valueOf(CollectionUtils.getLargest(ids) + 1));
// }
// }
BreakerConfig config = dao.getConfig(100);
/* TimeZone tz = TimeZone.getTimeZone("America/Chicago");
BillingRate summer0 = new BillingRate();
summer0.setMeter(-1);
summer0.setDayBillingCycleStart(13);
summer0.setFlow(GridFlow.BOTH);
summer0.setRate(0.13806);
summer0.setCurrency(BillingCurrency.DOLLAR);
summer0.setBeginEffective(DateUtils.date(5, 16, 2021, tz));
summer0.setEndEffective(DateUtils.date(9, 16, 2021, tz));
summer0.setRecursAnnually(true);
BillingRate winter0 = summer0.duplicate();
winter0.setMonthKWhEnd(1000);
winter0.setRate(0.09703);
winter0.setBeginEffective(DateUtils.date(9, 16, 2021, tz));
winter0.setEndEffective(DateUtils.date(5, 16, 2022, tz));
BillingRate winter1 = winter0.duplicate();
winter1.setMonthKWhStart(1000);
winter1.setMonthKWhEnd(0);
winter1.setRate(0.063);
config.setBillingRates(CollectionUtils.asArrayList(summer0, winter0, winter1));*/
IFilter<Breaker> filter = _b->_b.getName().contains("Water") || _b.getName().contains("Furnace") || _b.getName().contains("Basement HP");
CollectionUtils.filter(config.getAllBreakers(), filter).forEach(_b->_b.setMeter(0));
CollectionUtils.filter(config.getAllBreakers(), _b->!filter.isFiltered(_b)).forEach(_b->_b.setMeter(1));
dao.putConfig(config);
dao.shutdown();
}
@@ -1,10 +1,10 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
public class CreateMongoConfig {
public static void main(String[] args) {
new MongoConfig("localhost", "*redacted*", "*redacted*", "CURRENT_MONITOR").saveToDisk(LanternFiles.OPS_PATH + "mongo.cfg");
new MongoConfig("lanternsoftware.com", "*redacted*", "*redacted*", "CURRENT_MONITOR").saveToDisk(LanternFiles.CONFIG_PATH + "mongo.cfg");
}
}
@@ -1,13 +1,13 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.dao.generator.DaoSerializerGenerator;
import com.lanternsoftware.util.dao.generator.SwiftModelGenerator;
public class CurrentMonitorSerializers {
public static void main(String[] args) {
DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_PATH + "currentmonitor", true, null);
SwiftModelGenerator.generateModel(LanternFiles.SOURCE_PATH + "currentmonitor", LanternFiles.SOURCE_PATH + "iOS");
DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_CODE_PATH + "currentmonitor", true, null);
SwiftModelGenerator.generateModel(LanternFiles.SOURCE_CODE_PATH + "currentmonitor", LanternFiles.SOURCE_CODE_PATH + "iOS");
}
}
@@ -2,21 +2,21 @@ package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupEnergy;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupSummary;
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
import com.lanternsoftware.datamodel.currentmonitor.EnergyTotal;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
public class MigrateSummaries {
public static void main(String[] args) {
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
// TimeZone tz = TimeZone.getTimeZone("America/Chicago");
// List<BreakerGroupEnergy> summaries = dao.getProxy().query(BreakerGroupEnergy.class, null);
// CollectionUtils.edit(summaries, _s->CollectionUtils.edit(_s.getAllGroups(), _t->_t.setAccountId(1)));
// dao.getProxy().save(summaries);
dao.getProxy().save(CollectionUtils.transform(dao.getProxy().queryAll(BreakerGroupEnergy.class), BreakerGroupSummary::new));
dao.getProxy().save(CollectionUtils.transform(dao.getProxy().queryAll(EnergySummary.class), EnergyTotal::new));
// List<BreakerPower> readings = null;
// while ((readings == null) || !readings.isEmpty()) {
@@ -2,24 +2,28 @@ package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import java.util.TimeZone;
public class RebuildSummaries {
public static void main(String[] args) {
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
dao.rebuildSummaries(100, DateUtils.date(8,3,2021, tz), DateUtils.date(8,5,2021, tz));
/* List<Account> accounts = dao.getProxy().queryAll(Account.class);
for (int accountId : CollectionUtils.transform(accounts, Account::getId)) {
if (accountId != 100)
continue;
dao.rebuildSummaries(accountId, DateUtils.date(4,21,2021, tz), DateUtils.date(4,22,2021, tz));
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
for (Account a : dao.getProxy().queryAll(Account.class)) {
TimeZone tz = DateUtils.fromTimeZoneId(a.getTimezone());
// BreakerConfig config = dao.getConfig(a.getId());
// BillingPlan plan = new BillingPlan();
// plan.setPlanId(1);
// plan.setBillingDay(1);
// plan.setName("Standard");
// plan.setRates(config.getBillingRates());
// config.setBillingPlans(CollectionUtils.asArrayList(plan));
// dao.putConfig(config);
dao.rebuildSummaries(a.getId(), DateUtils.date(12,18,2021,tz), DateUtils.date(12,19,2021,tz));
}
*/
dao.shutdown();
}
}