mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Allow exporting all data in bson, json, or csv formats.
This commit is contained in:
parent
eeec6cc697
commit
eaf1e4504f
Binary file not shown.
Binary file not shown.
|
@ -28,10 +28,14 @@ public class LEDFlasher implements Runnable {
|
|||
|
||||
public static void setLEDOn(boolean _on) {
|
||||
try {
|
||||
if (_on)
|
||||
if (_on) {
|
||||
Runtime.getRuntime().exec(new String[]{"sh", "-c", "echo default-on > /sys/class/leds/led0/trigger"});
|
||||
Runtime.getRuntime().exec(new String[]{"sh", "-c", "echo default-on > /sys/class/leds/led1/trigger"});
|
||||
else
|
||||
}
|
||||
else {
|
||||
Runtime.getRuntime().exec(new String[]{"sh", "-c", "echo none > /sys/class/leds/led0/trigger"});
|
||||
Runtime.getRuntime().exec(new String[]{"sh", "-c", "echo none > /sys/class/leds/led1/trigger"});
|
||||
}
|
||||
}
|
||||
catch (Exception _e) {
|
||||
LOG.error("Failed to change LED state", _e);
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.lanternsoftware.currentmonitor;
|
|||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.ResourceLoader;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
|
||||
|
@ -23,6 +23,6 @@ public class CreateConfig {
|
|||
b1.setPort(1);
|
||||
b1.setSizeAmps(20);
|
||||
c.setMqttBreakers(CollectionUtils.asArrayList(b1));
|
||||
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "mqtt1.json", DaoSerializer.toJson(c));
|
||||
ResourceLoader.writeFile(LanternFiles.CONFIG_PATH + "mqtt1.json", DaoSerializer.toJson(c));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.generator.DaoSerializerGenerator;
|
||||
|
||||
public class CurrentMonitorAppSerializers {
|
||||
public static void main(String[] args) {
|
||||
DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_PATH + "currentmonitor", true, null);
|
||||
DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_CODE_PATH + "currentmonitor", true, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.ResourceLoader;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
|
@ -9,18 +9,17 @@ import com.lanternsoftware.util.xml.XmlParser;
|
|||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
public class ReleaseCurrentMonitor {
|
||||
public static void main(String[] args) {
|
||||
XmlNode pom = XmlParser.loadXmlFile(LanternFiles.SOURCE_PATH + "currentmonitor" + File.separator + "lantern-currentmonitor" + File.separator + "pom.xml");
|
||||
XmlNode pom = XmlParser.loadXmlFile(LanternFiles.SOURCE_CODE_PATH + "currentmonitor" + File.separator + "lantern-currentmonitor" + File.separator + "pom.xml");
|
||||
if (pom == null)
|
||||
return;
|
||||
XmlNode versionNode = pom.getChild(Collections.singletonList("version"));
|
||||
String version = versionNode.getContent();
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.directory(new File(LanternFiles.SOURCE_PATH));
|
||||
builder.directory(new File(LanternFiles.SOURCE_CODE_PATH));
|
||||
builder.command("cmd.exe", "/c", "mvn clean install");
|
||||
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
try {
|
||||
|
@ -30,9 +29,9 @@ public class ReleaseCurrentMonitor {
|
|||
} catch (Exception _e) {
|
||||
_e.printStackTrace();
|
||||
}
|
||||
byte[] jar = ResourceLoader.loadFile(LanternFiles.SOURCE_PATH + "currentmonitor" + File.separator + "lantern-currentmonitor" + File.separator + "target" + File.separator + "lantern-currentmonitor.jar");
|
||||
byte[] jar = ResourceLoader.loadFile(LanternFiles.SOURCE_CODE_PATH + "currentmonitor" + File.separator + "lantern-currentmonitor" + File.separator + "target" + File.separator + "lantern-currentmonitor.jar");
|
||||
DaoEntity meta = new DaoEntity("version", version).and("size", jar.length).and("checksum", DigestUtils.md5Hex(jar));
|
||||
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "release" + File.separator + "lantern-currentmonitor.jar", jar);
|
||||
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "release" + File.separator + "version.json", DaoSerializer.toJson(meta));
|
||||
ResourceLoader.writeFile(LanternFiles.CONFIG_PATH + "release" + File.separator + "lantern-currentmonitor.jar", jar);
|
||||
ResourceLoader.writeFile(LanternFiles.CONFIG_PATH + "release" + File.separator + "version.json", DaoSerializer.toJson(meta));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import com.lanternsoftware.datamodel.rules.Event;
|
|||
import com.lanternsoftware.datamodel.rules.FcmDevice;
|
||||
import com.lanternsoftware.datamodel.rules.Rule;
|
||||
import com.lanternsoftware.util.DebugTimer;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.DaoQuery;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
|
||||
|
@ -19,8 +19,8 @@ import java.util.List;
|
|||
|
||||
public class Backup {
|
||||
public static void main(String[] args) {
|
||||
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_SOURCE + "mongo.cfg"));
|
||||
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST + "mongo.cfg"));
|
||||
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
|
||||
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST_PATH + "mongo.cfg"));
|
||||
|
||||
DebugTimer t1 = new DebugTimer("Query Accounts");
|
||||
List<Account> accounts = dao.getProxy().queryAll(Account.class);
|
||||
|
|
|
@ -4,7 +4,7 @@ import com.lanternsoftware.datamodel.currentmonitor.Account;
|
|||
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.DebugTimer;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.dao.DaoQuery;
|
||||
import com.lanternsoftware.util.dao.DaoSort;
|
||||
|
@ -16,8 +16,8 @@ import java.util.TimeZone;
|
|||
|
||||
public class BackupMinutes {
|
||||
public static void main(String[] args) {
|
||||
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_SOURCE + "mongo.cfg"));
|
||||
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST + "mongo.cfg"));
|
||||
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
|
||||
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST_PATH + "mongo.cfg"));
|
||||
Date now = new Date();
|
||||
for (Account a : dao.getProxy().queryAll(Account.class)) {
|
||||
if (a.getId() == 0)
|
||||
|
|
|
@ -7,9 +7,12 @@ import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
|
|||
import com.lanternsoftware.datamodel.currentmonitor.EnergyViewMode;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.archive.ArchiveStatus;
|
||||
import com.lanternsoftware.util.DateRange;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoProxy;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
@ -26,6 +29,15 @@ public interface CurrentMonitorDao {
|
|||
void putEnergySummary(EnergySummary _energy);
|
||||
|
||||
void putHubPowerMinute(HubPowerMinute _power);
|
||||
Iterable<HubPowerMinute> streamHubPowerMinutes(int _accountId, Date _start, Date _end);
|
||||
|
||||
void archiveMonth(int _accountId, Date _month);
|
||||
InputStream streamArchive(int _accountId, Date _month);
|
||||
void putArchiveStatus(ArchiveStatus _status);
|
||||
void deleteArchiveStatus(int _accountId, Date _month);
|
||||
List<ArchiveStatus> getArchiveStatus(int _accountId);
|
||||
|
||||
DateRange getMonitoredDateRange(int _accountId);
|
||||
|
||||
BreakerConfig getConfig(int _accountId);
|
||||
BreakerConfig getMergedConfig(AuthCode _authCode);
|
||||
|
|
|
@ -2,12 +2,13 @@ package com.lanternsoftware.dataaccess.currentmonitor;
|
|||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Account;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BillingPlan;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BillingRate;
|
||||
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.BreakerPower;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerPowerMinute;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerType;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.ChargeSummary;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.ChargeTotal;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
|
||||
|
@ -16,7 +17,12 @@ import com.lanternsoftware.datamodel.currentmonitor.EnergyViewMode;
|
|||
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Sequence;
|
||||
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.DateRange;
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.DebugTimer;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
|
@ -28,24 +34,41 @@ import com.lanternsoftware.util.dao.DaoSort;
|
|||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoProxy;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.mutable.MutableDouble;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.mindrot.jbcrypt.BCrypt;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MongoCurrentMonitorDao.class);
|
||||
|
@ -65,6 +88,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
|||
proxy.ensureIndex(ChargeSummary.class, DaoSort.sort("account_id").then("plan_id").then("group_id").then("view_mode"));
|
||||
proxy.ensureIndex(ChargeTotal.class, DaoSort.sort("account_id").then("plan_id").then("group_id").then("view_mode").then("start"));
|
||||
proxy.ensureIndex(DirtyMinute.class, DaoSort.sort("posted"));
|
||||
proxy.ensureIndex(ArchiveStatus.class, DaoSort.sort("account_id"));
|
||||
for (DirtyMinute minute : proxy.queryAll(DirtyMinute.class)) {
|
||||
updateEnergySummaries(minute);
|
||||
}
|
||||
|
@ -100,6 +124,196 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
|||
}, 10000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<HubPowerMinute> streamHubPowerMinutes(int _accountId, Date _start, Date _end) {
|
||||
return proxy.queryIterator(HubPowerMinute.class, new DaoQuery("account_id", _accountId).andBetweenInclusiveExclusive("minute", DateUtils.toLong(_start)/60000, DateUtils.toLong(_end)/60000), null, DaoSort.sort("start"), 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void archiveMonth(int _accountId, Date _month) {
|
||||
ArchiveStatus status = new ArchiveStatus();
|
||||
status.setAccountId(_accountId);
|
||||
status.setMonth(_month);
|
||||
status.setProgress(1);
|
||||
putArchiveStatus(status);
|
||||
executor.submit(()->{
|
||||
synchronized (MongoCurrentMonitorDao.this) {
|
||||
TimeZone tz = getTimeZoneForAccount(_accountId);
|
||||
DebugTimer timer = new DebugTimer("Monthly Archive Generation for account " + _accountId + " month " + DateUtils.format("MMMM yyyy", tz, _month));
|
||||
Date start = _month;
|
||||
Date end = DateUtils.getEndOfMonth(_month, tz);
|
||||
BreakerConfig config = getConfig(_accountId); //TODO: get historical config for archive month in case it's changed since then.
|
||||
List<Breaker> breakers = CollectionUtils.filter(config.getAllBreakers(), _b -> !NullUtils.isOneOf(_b.getType(), BreakerType.DOUBLE_POLE_BOTTOM, BreakerType.EMPTY));
|
||||
breakers.sort(Comparator.comparing(Breaker::getPanel).thenComparing(Breaker::getSpace));
|
||||
Map<Integer, Integer> breakerKeys = CollectionUtils.transformToMap(config.getAllBreakers(), Breaker::getIntKey, _b -> Breaker.intKey(_b.getPanel(), _b.getType() == BreakerType.DOUBLE_POLE_BOTTOM ? _b.getSpace() - 2 : _b.getSpace()));
|
||||
Map<Integer, List<Float>> minuteReadings = new HashMap<>();
|
||||
MonthlyEnergyArchive archive = new MonthlyEnergyArchive();
|
||||
archive.setAccountId(_accountId);
|
||||
archive.setMonth(start);
|
||||
List<DailyEnergyArchive> days = new ArrayList<>();
|
||||
archive.setDays(days);
|
||||
while (start.before(end)) {
|
||||
Map<Integer, byte[]> dayReadings = new HashMap<>();
|
||||
Date dayEnd = DateUtils.addDays(start, 1, tz);
|
||||
int minute = 0;
|
||||
int bytesInDay = (int) (4 * DateUtils.diffInSeconds(start, dayEnd));
|
||||
Iterator<HubPowerMinute> i = streamHubPowerMinutes(_accountId, start, dayEnd).iterator();
|
||||
HubPowerMinute m = null;
|
||||
if (i.hasNext())
|
||||
m = i.next();
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
df.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
while (i.hasNext()) {
|
||||
if (m == null)
|
||||
break;
|
||||
for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(m.getBreakers())) {
|
||||
if (!breakerKeys.containsKey(breaker.breakerIntKey()))
|
||||
continue;
|
||||
int key = breakerKeys.get(breaker.breakerIntKey());
|
||||
List<Float> r = minuteReadings.get(key);
|
||||
if (r == null)
|
||||
minuteReadings.put(key, breaker.getReadings());
|
||||
else {
|
||||
for (int idx = 0; idx < minuteReadings.size(); idx++) {
|
||||
r.set(idx, r.get(idx) + breaker.getReadings().get(idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
HubPowerMinute cur = i.next();
|
||||
if (cur.getMinute() != m.getMinute()) {
|
||||
addReadings(minute, bytesInDay, minuteReadings, dayReadings);
|
||||
minute++;
|
||||
}
|
||||
m = cur;
|
||||
}
|
||||
if (m != null)
|
||||
addReadings(minute, bytesInDay, minuteReadings, dayReadings);
|
||||
List<BreakerEnergyArchive> breakerEnergies = new ArrayList<>();
|
||||
for (Entry<Integer, byte[]> be : dayReadings.entrySet()) {
|
||||
BreakerEnergyArchive breakerEnergy = new BreakerEnergyArchive();
|
||||
breakerEnergy.setPanel(Breaker.intKeyToPanel(be.getKey()));
|
||||
breakerEnergy.setSpace(Breaker.intKeyToSpace(be.getKey()));
|
||||
breakerEnergy.setReadings(be.getValue());
|
||||
breakerEnergies.add(breakerEnergy);
|
||||
}
|
||||
DailyEnergyArchive day = new DailyEnergyArchive();
|
||||
day.setBreakers(breakerEnergies);
|
||||
days.add(day);
|
||||
start = dayEnd;
|
||||
status.setProgress(50f * (start.getTime() - _month.getTime()) / (end.getTime() - _month.getTime()));
|
||||
putArchiveStatus(status);
|
||||
}
|
||||
timer.stop();
|
||||
DebugTimer t = new DebugTimer("Convert Archive to bson for account " + archive.getAccountId());
|
||||
byte[] bson = DaoSerializer.toBson(archive);
|
||||
t.stop();
|
||||
|
||||
DebugTimer t2 = new DebugTimer("Zip Archive and write to disk for account" + archive.getAccountId());
|
||||
OutputStream os = null;
|
||||
try {
|
||||
File partialPath = new File(LanternFiles.BACKUP_DEST_PATH + archive.getAccountId()+File.separator + "partial");
|
||||
FileUtils.deleteDirectory(partialPath);
|
||||
partialPath.mkdirs();
|
||||
String backupPath = LanternFiles.BACKUP_DEST_PATH + archive.getAccountId() + File.separator;
|
||||
if (!archive.isComplete(tz))
|
||||
backupPath += "partial" + File.separator;
|
||||
os = new GZIPOutputStream(new FileOutputStream(backupPath + archive.getMonth().getTime() + ".zip")) {{def.setLevel(Deflater.BEST_SPEED);}};
|
||||
int batchSize = bson.length / 50;
|
||||
for (int offset = 0; offset < bson.length; offset += batchSize) {
|
||||
os.write(bson, offset, Math.min(batchSize, bson.length - offset));
|
||||
status.setProgress(50 + (50f * offset / bson.length));
|
||||
putArchiveStatus(status);
|
||||
}
|
||||
} catch (Exception _e) {
|
||||
logger.error("Failed to write export file", _e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
t2.stop();
|
||||
deleteArchiveStatus(_accountId, _month);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addReadings(int _minuteInDay, int _bytesInDay, Map<Integer, List<Float>> _minuteReadings, Map<Integer, byte[]> _dayReadings) {
|
||||
for (Entry<Integer, List<Float>> entry : _minuteReadings.entrySet()) {
|
||||
byte[] dayBytes = _dayReadings.computeIfAbsent(entry.getKey(), _r->new byte[_bytesInDay]);
|
||||
ByteBuffer bb = ByteBuffer.wrap(dayBytes);
|
||||
for (int fl = 0; fl < CollectionUtils.size(entry.getValue()); fl++) {
|
||||
bb.putFloat(_minuteInDay*240 + (fl*4), CollectionUtils.get(entry.getValue(), fl));
|
||||
}
|
||||
}
|
||||
_minuteReadings.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream streamArchive(int _accountId, Date _month) {
|
||||
try {
|
||||
String complete = LanternFiles.BACKUP_DEST_PATH + _accountId + File.separator + _month.getTime() + ".zip";
|
||||
if (new File(complete).exists())
|
||||
return new FileInputStream(complete);
|
||||
String partial = LanternFiles.BACKUP_DEST_PATH + _accountId + File.separator + "partial" + File.separator + _month.getTime() + ".zip";
|
||||
if (new File(partial).exists())
|
||||
return new FileInputStream(partial);
|
||||
}
|
||||
catch (Exception _e) {
|
||||
logger.error("Failed to load archive", _e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putArchiveStatus(ArchiveStatus _status) {
|
||||
proxy.save(_status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteArchiveStatus(int _accountId, Date _month) {
|
||||
proxy.delete(ArchiveStatus.class, new DaoQuery("_id", MonthlyEnergyArchive.toId(_accountId, _month)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArchiveStatus> getArchiveStatus(int _accountId) {
|
||||
Map<Date, ArchiveStatus> statuses = CollectionUtils.transformToSortedMap(proxy.query(ArchiveStatus.class, new DaoQuery("account_id", _accountId)), ArchiveStatus::getMonth);
|
||||
File folder = new File(LanternFiles.BACKUP_DEST_PATH + _accountId);
|
||||
if (folder.exists()) {
|
||||
for (File file : CollectionUtils.asArrayList(folder.listFiles())) {
|
||||
if (file.isFile()) {
|
||||
Date month = new Date(DaoSerializer.toLong(file.getName().replace(".zip", "")));
|
||||
statuses.computeIfAbsent(month, _m -> new ArchiveStatus(_accountId, _m, 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
File partial = new File(LanternFiles.BACKUP_DEST_PATH + _accountId + File.separator + "partial");
|
||||
if (partial.exists()) {
|
||||
for (File file : CollectionUtils.asArrayList(partial.listFiles())) {
|
||||
if (file.isFile() && (new Date().getTime() - file.lastModified() < 86400000)) {
|
||||
Date month = new Date(DaoSerializer.toLong(file.getName().replace(".zip", "")));
|
||||
statuses.computeIfAbsent(month, _m -> new ArchiveStatus(_accountId, _m, 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
DateRange range = getMonitoredDateRange(_accountId);
|
||||
TimeZone tz = getTimeZoneForAccount(_accountId);
|
||||
Date month = DateUtils.getStartOfMonth(range.getStart(), tz);
|
||||
Date end = DateUtils.getEndOfMonth(range.getEnd(), tz);
|
||||
while (month.before(end)) {
|
||||
statuses.computeIfAbsent(month, _m->new ArchiveStatus(_accountId, _m, 0));
|
||||
month = DateUtils.addMonths(month, 1, tz);
|
||||
}
|
||||
return new ArrayList<>(statuses.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateRange getMonitoredDateRange(int _accountId) {
|
||||
DaoQuery query = new DaoQuery("account_id", _accountId).and("view_mode", EnergyViewMode.MONTH.name());
|
||||
EnergySummary first = proxy.queryOne(EnergySummary.class, query, DaoSort.sort("start"));
|
||||
EnergySummary last = proxy.queryOne(EnergySummary.class, query, DaoSort.sortDesc("start"));
|
||||
if ((first != null) && (last != null))
|
||||
return new DateRange(first.getStart(), last.getStart());
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateEnergySummaries(DirtyMinute _minute) {
|
||||
DebugTimer timer = new DebugTimer("Updating summaries", logger);
|
||||
List<HubPowerMinute> minutes = proxy.query(HubPowerMinute.class, new DaoQuery("account_id", _minute.getAccountId()).and("minute", _minute.getMinute()));
|
||||
|
@ -262,32 +476,6 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
|||
}
|
||||
}
|
||||
|
||||
private void rebuildSummaries(int _accountId, Collection<BillingRate> _rates) {
|
||||
logger.info("Rebuilding summaries due to a change in {} rates", CollectionUtils.size(_rates));
|
||||
HubPowerMinute firstMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sort("minute"));
|
||||
if (firstMinute == null)
|
||||
return;
|
||||
TimeZone tz = getTimeZoneForAccount(_accountId);
|
||||
Map<String, BillingRate> rates = CollectionUtils.transformToMap(_rates, _r -> String.format("%d%d", DaoSerializer.toLong(_r.getBeginEffective()), DaoSerializer.toLong(_r.getEndEffective())));
|
||||
for (BillingRate rate : rates.values()) {
|
||||
Date start = rate.getBeginEffective();
|
||||
Date end = rate.getEndEffective();
|
||||
Date now = new Date();
|
||||
if ((start == null) || start.before(firstMinute.getMinuteAsDate()))
|
||||
start = firstMinute.getMinuteAsDate();
|
||||
if ((end == null) || end.after(now))
|
||||
end = now;
|
||||
rebuildSummaries(_accountId, start, end);
|
||||
if (rate.isRecursAnnually()) {
|
||||
while (end.before(now)) {
|
||||
start = DateUtils.addYears(start, 1, tz);
|
||||
end = DateUtils.addYears(end, 1, tz);
|
||||
rebuildSummaries(_accountId, start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebuildSummariesAsync(int _accountId) {
|
||||
executor.submit(() -> rebuildSummaries(_accountId));
|
||||
|
@ -488,13 +676,13 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
|||
public String getAuthCodeForEmail(String _email, TimeZone _tz) {
|
||||
_email = _email.toLowerCase().trim();
|
||||
Account account = getAccountByUsername(_email);
|
||||
if (account == null) {
|
||||
if ((account == null) && (_tz != null)) {
|
||||
account = new Account();
|
||||
account.setUsername(_email);
|
||||
account.setTimezone(_tz.getID());
|
||||
putAccount(account);
|
||||
}
|
||||
return toAuthCode(account.getId(), account.getAuxiliaryAccountIds());
|
||||
return (account == null)?null:toAuthCode(account.getId(), account.getAuxiliaryAccountIds());
|
||||
}
|
||||
|
||||
public String toAuthCode(int _acctId, List<Integer> _auxAcctIds) {
|
||||
|
|
|
@ -194,10 +194,26 @@ public class Breaker implements IIdentical<Breaker> {
|
|||
return key;
|
||||
}
|
||||
|
||||
public int getIntKey() {
|
||||
return intKey(panel, space);
|
||||
}
|
||||
|
||||
public static int intKeyToPanel(int _intKey) {
|
||||
return _intKey/10000;
|
||||
}
|
||||
|
||||
public static int intKeyToSpace(int _intKey) {
|
||||
return _intKey%10000;
|
||||
}
|
||||
|
||||
public static String key(int _panel, int _space) {
|
||||
return String.format("%d-%d", _panel, _space);
|
||||
}
|
||||
|
||||
public static int intKey(int _panel, int _space) {
|
||||
return 10000*_panel + _space;
|
||||
}
|
||||
|
||||
public static int portToChip(int _port) {
|
||||
return (_port < 9) ? 1 : 0;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,10 @@ public class BreakerPowerMinute {
|
|||
return Breaker.key(panel, space);
|
||||
}
|
||||
|
||||
public int breakerIntKey() {
|
||||
return Breaker.intKey(panel, space);
|
||||
}
|
||||
|
||||
public List<Float> getReadings() {
|
||||
return readings;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package com.lanternsoftware.datamodel.currentmonitor.archive;
|
||||
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@DBSerializable(autogen = false)
|
||||
public class ArchiveStatus {
|
||||
private int accountId;
|
||||
private Date month;
|
||||
private float progress;
|
||||
|
||||
public ArchiveStatus() {
|
||||
}
|
||||
|
||||
public ArchiveStatus(int _accountId, Date _month, float _progress) {
|
||||
accountId = _accountId;
|
||||
month = _month;
|
||||
progress = _progress;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return String.format("%d-%d", accountId, DateUtils.toLong(month));
|
||||
}
|
||||
|
||||
public int getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(int _accountId) {
|
||||
accountId = _accountId;
|
||||
}
|
||||
|
||||
public Date getMonth() {
|
||||
return month;
|
||||
}
|
||||
|
||||
public void setMonth(Date _month) {
|
||||
month = _month;
|
||||
}
|
||||
|
||||
public float getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
public void setProgress(float _progress) {
|
||||
progress = _progress;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.lanternsoftware.datamodel.currentmonitor.archive;
|
||||
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
|
||||
@DBSerializable
|
||||
public class BreakerEnergyArchive {
|
||||
private int panel;
|
||||
private int space;
|
||||
private byte[] readings;
|
||||
|
||||
public int getPanel() {
|
||||
return panel;
|
||||
}
|
||||
|
||||
public void setPanel(int _panel) {
|
||||
panel = _panel;
|
||||
}
|
||||
|
||||
public int getSpace() {
|
||||
return space;
|
||||
}
|
||||
|
||||
public void setSpace(int _space) {
|
||||
space = _space;
|
||||
}
|
||||
|
||||
public byte[] getReadings() {
|
||||
return readings;
|
||||
}
|
||||
|
||||
public void setReadings(byte[] _readings) {
|
||||
readings = _readings;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.lanternsoftware.datamodel.currentmonitor.archive;
|
||||
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@DBSerializable
|
||||
public class DailyEnergyArchive {
|
||||
private List<BreakerEnergyArchive> breakers;
|
||||
|
||||
public List<BreakerEnergyArchive> getBreakers() {
|
||||
return breakers;
|
||||
}
|
||||
|
||||
public void setBreakers(List<BreakerEnergyArchive> _breakers) {
|
||||
breakers = _breakers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.lanternsoftware.datamodel.currentmonitor.archive;
|
||||
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@DBSerializable(autogen = false)
|
||||
public class MonthlyEnergyArchive {
|
||||
private int accountId;
|
||||
private Date month;
|
||||
private List<DailyEnergyArchive> days;
|
||||
|
||||
public String getId() {
|
||||
return toId(accountId, month);
|
||||
}
|
||||
|
||||
public static String toId(int _accountId, Date _month) {
|
||||
return String.format("%d-%d", _accountId, DateUtils.toLong(_month));
|
||||
}
|
||||
|
||||
public int getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(int _accountId) {
|
||||
accountId = _accountId;
|
||||
}
|
||||
|
||||
public Date getMonth() {
|
||||
return month;
|
||||
}
|
||||
|
||||
public void setMonth(Date _month) {
|
||||
month = _month;
|
||||
}
|
||||
|
||||
public List<DailyEnergyArchive> getDays() {
|
||||
return days;
|
||||
}
|
||||
|
||||
public void setDays(List<DailyEnergyArchive> _days) {
|
||||
days = _days;
|
||||
}
|
||||
|
||||
public boolean isComplete(TimeZone _tz) {
|
||||
Date valid = DateUtils.addDays(new Date(), -7, _tz);
|
||||
valid = DateUtils.addMonths(valid, -1, _tz);
|
||||
return month.before(valid);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.lanternsoftware.datamodel.currentmonitor.archive.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.archive.ArchiveStatus;
|
||||
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoProxyType;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ArchiveStatusSerializer extends AbstractDaoSerializer<ArchiveStatus>
|
||||
{
|
||||
@Override
|
||||
public Class<ArchiveStatus> getSupportedClass()
|
||||
{
|
||||
return ArchiveStatus.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DaoProxyType> getSupportedProxies() {
|
||||
return Collections.singletonList(DaoProxyType.MONGO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoEntity toDaoEntity(ArchiveStatus _o)
|
||||
{
|
||||
DaoEntity d = new DaoEntity();
|
||||
d.put("_id", _o.getId());
|
||||
d.put("account_id", _o.getAccountId());
|
||||
d.put("month", DaoSerializer.toLong(_o.getMonth()));
|
||||
d.put("progress", _o.getProgress());
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArchiveStatus fromDaoEntity(DaoEntity _d)
|
||||
{
|
||||
ArchiveStatus o = new ArchiveStatus();
|
||||
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
|
||||
o.setMonth(DaoSerializer.getDate(_d, "month"));
|
||||
o.setProgress(DaoSerializer.getFloat(_d, "progress"));
|
||||
return o;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.lanternsoftware.datamodel.currentmonitor.archive.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.archive.BreakerEnergyArchive;
|
||||
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoProxyType;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class BreakerEnergyArchiveSerializer extends AbstractDaoSerializer<BreakerEnergyArchive>
|
||||
{
|
||||
@Override
|
||||
public Class<BreakerEnergyArchive> getSupportedClass()
|
||||
{
|
||||
return BreakerEnergyArchive.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DaoProxyType> getSupportedProxies() {
|
||||
return Collections.singletonList(DaoProxyType.MONGO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoEntity toDaoEntity(BreakerEnergyArchive _o)
|
||||
{
|
||||
DaoEntity d = new DaoEntity();
|
||||
d.put("panel", _o.getPanel());
|
||||
d.put("space", _o.getSpace());
|
||||
d.put("readings", _o.getReadings());
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BreakerEnergyArchive fromDaoEntity(DaoEntity _d)
|
||||
{
|
||||
BreakerEnergyArchive o = new BreakerEnergyArchive();
|
||||
o.setPanel(DaoSerializer.getInteger(_d, "panel"));
|
||||
o.setSpace(DaoSerializer.getInteger(_d, "space"));
|
||||
o.setReadings(DaoSerializer.getByteArray(_d, "readings"));
|
||||
return o;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.lanternsoftware.datamodel.currentmonitor.archive.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.archive.BreakerEnergyArchive;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.archive.DailyEnergyArchive;
|
||||
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoProxyType;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class DailyEnergyArchiveSerializer extends AbstractDaoSerializer<DailyEnergyArchive>
|
||||
{
|
||||
@Override
|
||||
public Class<DailyEnergyArchive> getSupportedClass()
|
||||
{
|
||||
return DailyEnergyArchive.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DaoProxyType> getSupportedProxies() {
|
||||
return Collections.singletonList(DaoProxyType.MONGO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoEntity toDaoEntity(DailyEnergyArchive _o)
|
||||
{
|
||||
DaoEntity d = new DaoEntity();
|
||||
d.put("breakers", DaoSerializer.toDaoEntities(_o.getBreakers(), DaoProxyType.MONGO));
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DailyEnergyArchive fromDaoEntity(DaoEntity _d)
|
||||
{
|
||||
DailyEnergyArchive o = new DailyEnergyArchive();
|
||||
o.setBreakers(DaoSerializer.getList(_d, "breakers", BreakerEnergyArchive.class));
|
||||
return o;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.lanternsoftware.datamodel.currentmonitor.archive.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.archive.DailyEnergyArchive;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.archive.MonthlyEnergyArchive;
|
||||
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoProxyType;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MonthlyEnergyArchiveSerializer extends AbstractDaoSerializer<MonthlyEnergyArchive>
|
||||
{
|
||||
@Override
|
||||
public Class<MonthlyEnergyArchive> getSupportedClass()
|
||||
{
|
||||
return MonthlyEnergyArchive.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DaoProxyType> getSupportedProxies() {
|
||||
return Collections.singletonList(DaoProxyType.MONGO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoEntity toDaoEntity(MonthlyEnergyArchive _o)
|
||||
{
|
||||
DaoEntity d = new DaoEntity();
|
||||
d.put("_id", _o.getId());
|
||||
d.put("account_id", _o.getAccountId());
|
||||
d.put("month", DaoSerializer.toLong(_o.getMonth()));
|
||||
d.put("days", DaoSerializer.toDaoEntities(_o.getDays(), DaoProxyType.MONGO));
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonthlyEnergyArchive fromDaoEntity(DaoEntity _d)
|
||||
{
|
||||
MonthlyEnergyArchive o = new MonthlyEnergyArchive();
|
||||
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
|
||||
o.setMonth(DaoSerializer.getDate(_d, "month"));
|
||||
o.setDays(DaoSerializer.getList(_d, "days", DailyEnergyArchive.class));
|
||||
return o;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
com.lanternsoftware.datamodel.currentmonitor.archive.dao.ArchiveStatusSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.archive.dao.BreakerEnergyArchiveSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.archive.dao.DailyEnergyArchiveSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.archive.dao.MonthlyEnergyArchiveSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.dao.AccountSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.dao.BillingPlanSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.dao.BillingRateSerializer
|
||||
|
|
|
@ -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
5050
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-grid.rtl.css
vendored
Normal file
5050
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-grid.rtl.css
vendored
Normal file
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
|
@ -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
478
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-reboot.rtl.css
vendored
Normal file
478
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-reboot.rtl.css
vendored
Normal file
|
@ -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
4866
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-utilities.css
vendored
Normal file
4866
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-utilities.css
vendored
Normal file
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
4857
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-utilities.rtl.css
vendored
Normal file
4857
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-utilities.rtl.css
vendored
Normal file
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
11198
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap.rtl.css
vendored
Normal file
11198
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap.rtl.css
vendored
Normal file
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;
|
||||
}
|
1
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/style.min.css
vendored
Normal file
1
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/style.min.css
vendored
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import com.lanternsoftware.datamodel.rules.Rule;
|
|||
import com.lanternsoftware.rules.actions.ActionImpl;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -54,8 +54,8 @@ public class RulesEngine {
|
|||
|
||||
public RulesEngine() {
|
||||
ServiceLoader.load(ActionImpl.class).forEach(_action->actions.put(_action.getType(), _action));
|
||||
dao = new MongoRulesDataAccess(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
||||
cmDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
||||
dao = new MongoRulesDataAccess(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
|
||||
cmDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
|
||||
timer = new Timer("RulesEngine Timer");
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import com.lanternsoftware.datamodel.rules.Alert;
|
|||
import com.lanternsoftware.datamodel.rules.FcmDevice;
|
||||
import com.lanternsoftware.datamodel.rules.Rule;
|
||||
import com.lanternsoftware.rules.RulesEngine;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -25,7 +25,7 @@ public abstract class AbstractAlertAction implements ActionImpl {
|
|||
static {
|
||||
FirebaseMessaging m = null;
|
||||
try {
|
||||
FileInputStream is = new FileInputStream(LanternFiles.OPS_PATH + "google_account_key.json");
|
||||
FileInputStream is = new FileInputStream(LanternFiles.CONFIG_PATH + "google_account_key.json");
|
||||
FirebaseOptions options = FirebaseOptions.builder().setCredentials(GoogleCredentials.fromStream(is)).build();
|
||||
m = FirebaseMessaging.getInstance(FirebaseApp.initializeApp(options));
|
||||
IOUtils.closeQuietly(is);
|
||||
|
|
|
@ -9,7 +9,7 @@ import com.lanternsoftware.dataaccess.rules.MongoRulesDataAccess;
|
|||
import com.lanternsoftware.dataaccess.rules.RulesDataAccess;
|
||||
import com.lanternsoftware.datamodel.rules.Alert;
|
||||
import com.lanternsoftware.datamodel.rules.FcmDevice;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.external.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -18,10 +18,12 @@ import java.io.FileInputStream;
|
|||
|
||||
public class TestSendAlert {
|
||||
public static void main(String[] args) {
|
||||
RulesDataAccess dao = new MongoRulesDataAccess(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
||||
RulesDataAccess dao = new MongoRulesDataAccess(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
|
||||
for (FcmDevice d : dao.getFcmDevicesForAccount(100)) {
|
||||
if (!d.getName().contains("Sony"))
|
||||
continue;
|
||||
Alert alert = new Alert();
|
||||
alert.setMessage("Test Alert");
|
||||
alert.setMessage("Garage Door 1 is still open");
|
||||
Message msg = Message.builder().setToken(d.getToken()).putData("payload", DaoSerializer.toBase64ZipBson(alert)).putData("payloadClass", Alert.class.getCanonicalName()).build();
|
||||
try {
|
||||
FileInputStream is = new FileInputStream("d:\\zwave\\firebase\\account_key.json");
|
||||
|
|
|
@ -607,29 +607,43 @@ public class CollectionUtils {
|
|||
return ret;
|
||||
}
|
||||
|
||||
public static <T, V extends Comparable<V>> Map<V, T> transformToSortedMap(Collection<T> _coll, ITransformer<? super T, V> _transformer) {
|
||||
return transformToMap(_coll, _transformer, new TreeMap<>());
|
||||
}
|
||||
|
||||
public static <T, V> Map<V, T> transformToMap(Collection<T> _coll, ITransformer<? super T, V> _transformer) {
|
||||
Map<V, T> mapValues = new HashMap<>();
|
||||
return transformToMap(_coll, _transformer, new HashMap<>());
|
||||
}
|
||||
|
||||
public static <T, V> Map<V, T> transformToMap(Collection<T> _coll, ITransformer<? super T, V> _transformer, Map<V, T> _map) {
|
||||
if ((_coll == null) || (_transformer == null))
|
||||
return mapValues;
|
||||
return _map;
|
||||
for (T t : _coll) {
|
||||
V v = _transformer.transform(t);
|
||||
if (v != null)
|
||||
mapValues.put(v, t);
|
||||
_map.put(v, t);
|
||||
}
|
||||
return mapValues;
|
||||
return _map;
|
||||
}
|
||||
|
||||
public static <T, V extends Comparable<V>, U> Map<V, U> transformToSortedMap(Collection<T> _coll, ITransformer<? super T, V> _keyTrans, ITransformer<? super T, U> _valTrans) {
|
||||
return transformToMap(_coll, _keyTrans, _valTrans, new TreeMap<>());
|
||||
}
|
||||
|
||||
public static <T, V, U> Map<V, U> transformToMap(Collection<T> _coll, ITransformer<? super T, V> _keyTrans, ITransformer<? super T, U> _valTrans) {
|
||||
Map<V, U> mapValues = new HashMap<>();
|
||||
return transformToMap(_coll, _keyTrans, _valTrans, new HashMap<>());
|
||||
}
|
||||
|
||||
public static <T, V, U> Map<V, U> transformToMap(Collection<T> _coll, ITransformer<? super T, V> _keyTrans, ITransformer<? super T, U> _valTrans, Map<V, U> _map) {
|
||||
if ((_coll == null) || (_keyTrans == null) || (_valTrans == null))
|
||||
return mapValues;
|
||||
return _map;
|
||||
for (T t : _coll) {
|
||||
V v = _keyTrans.transform(t);
|
||||
U u = _valTrans.transform(t);
|
||||
if ((v != null) && (u != null))
|
||||
mapValues.put(v, u);
|
||||
_map.put(v, u);
|
||||
}
|
||||
return mapValues;
|
||||
return _map;
|
||||
}
|
||||
|
||||
public static <T, V> Map<V, List<T>> transformToMultiMap(Collection<T> _coll, ITransformer<? super T, V> _transformer) {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.lanternsoftware.util;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class DateRange {
|
||||
private Date start;
|
||||
private Date end;
|
||||
|
||||
public DateRange() {
|
||||
}
|
||||
|
||||
public DateRange(Date _start, Date _end) {
|
||||
start = _start;
|
||||
end = _end;
|
||||
}
|
||||
|
||||
public Date getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(Date _start) {
|
||||
start = _start;
|
||||
}
|
||||
|
||||
public Date getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(Date _end) {
|
||||
end = _end;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user