Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
b4b125d750 | |||
826f0eaa73 | |||
adddef3188 | |||
3e2faf9554 | |||
744ad9211b | |||
35a116abbb | |||
4cb5b8d814 | |||
efb86cf6ce | |||
c6863293c5 | |||
ce582383c3 | |||
31053c1014 | |||
f5b891b966 | |||
74b8a42d29 | |||
8af6c65c9b | |||
e14097117f | |||
c6d8d14a1f | |||
ff3c1cf04e | |||
8ac1cdf476 | |||
c28eb7b240 | |||
31326d40c8 | |||
716f09681c | |||
ead77534ce | |||
c5daa76102 |
@ -1,3 +0,0 @@
|
|||||||
VUE_APP_PM_API_BASE=https://pmapi.jdb-labs.com/v0
|
|
||||||
VUE_APP_LOG_LEVEL=INFO
|
|
||||||
VUE_APP_API_LOG_LEVEL=ERROR
|
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -26,3 +26,9 @@ yarn-error.log*
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# Terrform files
|
||||||
|
.terraform/
|
||||||
|
|
||||||
|
# API Testing Files
|
||||||
|
api/temp/
|
||||||
|
14
Makefile
14
Makefile
@ -1,8 +1,13 @@
|
|||||||
VERSION:=$(shell git describe --always)
|
VERSION:=$(shell git describe --always)
|
||||||
TARGET_ENV=dev
|
TARGET_ENV ?= dev
|
||||||
|
|
||||||
build: dist/personal-measure-api.tar.gz dist/personal-measure-web.tar.gz
|
build: dist/personal-measure-api.tar.gz dist/personal-measure-web.tar.gz
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -r dist
|
||||||
|
-rm api/personal_measure_api
|
||||||
|
-rm -r web/dist
|
||||||
|
|
||||||
dist/personal-measure-api.tar.gz:
|
dist/personal-measure-api.tar.gz:
|
||||||
-mkdir dist
|
-mkdir dist
|
||||||
make -C api personal_measure_api
|
make -C api personal_measure_api
|
||||||
@ -11,7 +16,7 @@ dist/personal-measure-api.tar.gz:
|
|||||||
|
|
||||||
dist/personal-measure-web.tar.gz:
|
dist/personal-measure-web.tar.gz:
|
||||||
-mkdir dist
|
-mkdir dist
|
||||||
(TARGET_ENV=$(TARGET_ENV) ./set-env.sh make -C web build)
|
TARGET_ENV=$(TARGET_ENV) make -C web build
|
||||||
tar czf dist/personal-measure-web-${VERSION}.tar.gz -C web/dist .
|
tar czf dist/personal-measure-web-${VERSION}.tar.gz -C web/dist .
|
||||||
cp dist/personal-measure-web-${VERSION}.tar.gz dist/personal-measure-web.tar.gz
|
cp dist/personal-measure-web-${VERSION}.tar.gz dist/personal-measure-web.tar.gz
|
||||||
|
|
||||||
@ -31,8 +36,3 @@ deploy-web: dist/personal-measure-web.tar.gz
|
|||||||
rm -r temp-deploy
|
rm -r temp-deploy
|
||||||
|
|
||||||
deploy: deploy-api deploy-web
|
deploy: deploy-api deploy-web
|
||||||
|
|
||||||
clean:
|
|
||||||
-rm -r dist
|
|
||||||
-rm api/personal_measure_api
|
|
||||||
-rm -r web/dist
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
include "src/main/nim/personal_measure_apipkg/version.nim"
|
include "src/main/nim/personal_measure_apipkg/version.nim"
|
||||||
|
|
||||||
version = PM_API_VERSION
|
version = "0.8.0"
|
||||||
author = "Jonathan Bernard"
|
author = "Jonathan Bernard"
|
||||||
description = "JDB\'s Personal Measures API"
|
description = "JDB\'s Personal Measures API"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@ -14,7 +14,8 @@ skipExt = @["nim"]
|
|||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires @["nim >= 0.19.4", "bcrypt", "docopt >= 0.6.8", "isaac >= 0.1.3",
|
requires @["nim >= 0.19.4", "bcrypt", "docopt >= 0.6.8", "isaac >= 0.1.3",
|
||||||
"jester >= 0.4.1", "jwt", "tempfile", "uuids >= 0.1.10" ]
|
"jester >= 0.4.3", "jwt", "tempfile", "uuids >= 0.1.10" ]
|
||||||
|
|
||||||
requires "https://git.jdb-labs.com/jdb/nim-cli-utils.git >= 0.6.3"
|
requires "https://git.jdb-labs.com/jdb/nim-cli-utils.git >= 0.6.3"
|
||||||
requires "https://git.jdb-labs.com/jdb/nim-time-utils.git >= 0.5.0"
|
requires "https://git.jdb-labs.com/jdb/nim-time-utils.git >= 0.5.2"
|
||||||
|
requires "https://git.jdb-labs.com/jdb-labs/fiber-orm-nim.git >= 0.3.0"
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import asyncdispatch, base64, jester, json, jwt, logging, options, sequtils,
|
import asyncdispatch, base64, jester, json, jwt, logging, options, sequtils,
|
||||||
strutils, times, uuids
|
times, uuids
|
||||||
from unicode import capitalize
|
from unicode import capitalize
|
||||||
import timeutils except `<`
|
import strutils except capitalize
|
||||||
|
import timeutils
|
||||||
|
|
||||||
import ./db, ./configuration, ./models, ./service, ./version
|
import ./db, ./configuration, ./models, ./service, ./version
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ proc newSession*(user: User): Session =
|
|||||||
|
|
||||||
template halt(code: HttpCode,
|
template halt(code: HttpCode,
|
||||||
headers: RawHeaders,
|
headers: RawHeaders,
|
||||||
content: string): typed =
|
content: string) =
|
||||||
## Immediately replies with the specified request. This means any further
|
## Immediately replies with the specified request. This means any further
|
||||||
## code will not be executed after calling this template in the current
|
## code will not be executed after calling this template in the current
|
||||||
## route.
|
## route.
|
||||||
@ -69,11 +70,6 @@ template statusResp(code: HttpCode, details: string = "", headersToSend: RawHead
|
|||||||
}),
|
}),
|
||||||
headersToSend)
|
headersToSend)
|
||||||
|
|
||||||
template execptionResp(ex: ref Exception, details: string = ""): void =
|
|
||||||
when not defined(release): debug ex.getStackTrace()
|
|
||||||
error details & ":\n" & ex.msg
|
|
||||||
statusResp(Http500)
|
|
||||||
|
|
||||||
# internal JSON parsing utils
|
# internal JSON parsing utils
|
||||||
proc getIfExists(n: JsonNode, key: string): JsonNode =
|
proc getIfExists(n: JsonNode, key: string): JsonNode =
|
||||||
## convenience method to get a key from a JObject or return null
|
## convenience method to get a key from a JObject or return null
|
||||||
@ -481,7 +477,7 @@ proc start*(ctx: PMApiContext): void =
|
|||||||
|
|
||||||
let newMeasurement = Measurement(
|
let newMeasurement = Measurement(
|
||||||
measureId: measure.id,
|
measureId: measure.id,
|
||||||
value: jsonBody.getOrFail("value").getInt,
|
value: jsonBody.getOrFail("value").getFloat,
|
||||||
timestamp:
|
timestamp:
|
||||||
if jsonBody.hasKey("timestamp"): jsonBody["timestamp"].getStr.parseIso8601.utc
|
if jsonBody.hasKey("timestamp"): jsonBody["timestamp"].getStr.parseIso8601.utc
|
||||||
else: getTime().utc,
|
else: getTime().utc,
|
||||||
@ -520,7 +516,7 @@ proc start*(ctx: PMApiContext): void =
|
|||||||
let measure = ctx.getMeasureForSlug(session.user.id, @"slug")
|
let measure = ctx.getMeasureForSlug(session.user.id, @"slug")
|
||||||
var measurement = ctx.getMeasurementForMeasure(measure.id, parseUUID(@"id"))
|
var measurement = ctx.getMeasurementForMeasure(measure.id, parseUUID(@"id"))
|
||||||
let jsonBody = parseJson(request.body)
|
let jsonBody = parseJson(request.body)
|
||||||
if jsonBody.hasKey("value"): measurement.value = jsonBody["value"].getInt
|
if jsonBody.hasKey("value"): measurement.value = jsonBody["value"].getFloat
|
||||||
if jsonBody.hasKey("timestamp"): measurement.timestamp = jsonBody["timestamp"].getStr.parseIso8601
|
if jsonBody.hasKey("timestamp"): measurement.timestamp = jsonBody["timestamp"].getStr.parseIso8601
|
||||||
if jsonBody.hasKey("extData"): measurement.extData = jsonBody["extData"]
|
if jsonBody.hasKey("extData"): measurement.extData = jsonBody["extData"]
|
||||||
jsonResp($(%ctx.db.updateMeasurement(measurement)))
|
jsonResp($(%ctx.db.updateMeasurement(measurement)))
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import db_postgres, macros, options, postgres, sequtils, strutils,
|
import db_postgres, fiber_orm, uuids
|
||||||
times, timeutils, unicode, uuids
|
|
||||||
|
|
||||||
import ./models
|
import ./models
|
||||||
import ./db_common
|
|
||||||
|
|
||||||
export db_common.NotFoundError
|
export fiber_orm.NotFoundError
|
||||||
|
|
||||||
type
|
type
|
||||||
PMApiDb* = ref object
|
PMApiDb* = ref object
|
||||||
@ -14,18 +12,24 @@ type
|
|||||||
proc connect*(connString: string): PMApiDb =
|
proc connect*(connString: string): PMApiDb =
|
||||||
result = PMApiDb(conn: open("", "", "", connString))
|
result = PMApiDb(conn: open("", "", "", connString))
|
||||||
|
|
||||||
generateProcsForModels([User, ApiToken, Measure, Measurement, ClientLogEntry])
|
generateProcsForModels(PMApiDb, [
|
||||||
|
User,
|
||||||
|
ApiToken,
|
||||||
|
Measure,
|
||||||
|
Measurement,
|
||||||
|
ClientLogEntry
|
||||||
|
])
|
||||||
|
|
||||||
generateLookup(User, @["email"])
|
generateLookup(PMApiDb, User, @["email"])
|
||||||
|
|
||||||
generateLookup(ApiToken, @["userId"])
|
generateLookup(PMApiDb, ApiToken, @["userId"])
|
||||||
generateLookup(ApiToken, @["hashedToken"])
|
generateLookup(PMApiDb, ApiToken, @["hashedToken"])
|
||||||
|
|
||||||
generateLookup(Measure, @["userId"])
|
generateLookup(PMApiDb, Measure, @["userId"])
|
||||||
generateLookup(Measure, @["userId", "id"])
|
generateLookup(PMApiDb, Measure, @["userId", "id"])
|
||||||
generateLookup(Measure, @["userId", "slug"])
|
generateLookup(PMApiDb, Measure, @["userId", "slug"])
|
||||||
|
|
||||||
generateLookup(Measurement, @["measureId"])
|
generateLookup(PMApiDb, Measurement, @["measureId"])
|
||||||
generateLookup(Measurement, @["measureId", "id"])
|
generateLookup(PMApiDb, Measurement, @["measureId", "id"])
|
||||||
|
|
||||||
generateLookup(ClientLogEntry, @["userId"])
|
generateLookup(PMApiDb, ClientLogEntry, @["userId"])
|
||||||
|
@ -1,150 +0,0 @@
|
|||||||
import db_postgres, macros, options, sequtils, strutils, uuids
|
|
||||||
|
|
||||||
from unicode import capitalize
|
|
||||||
|
|
||||||
import ./db_util
|
|
||||||
|
|
||||||
type NotFoundError* = object of CatchableError
|
|
||||||
|
|
||||||
proc newMutateClauses(): MutateClauses =
|
|
||||||
return MutateClauses(
|
|
||||||
columns: @[],
|
|
||||||
placeholders: @[],
|
|
||||||
values: @[])
|
|
||||||
|
|
||||||
proc createRecord*[T](db: DbConn, rec: T): T =
|
|
||||||
var mc = newMutateClauses()
|
|
||||||
populateMutateClauses(rec, true, mc)
|
|
||||||
|
|
||||||
# Confusingly, getRow allows inserts and updates. We use it to get back the ID
|
|
||||||
# we want from the row.
|
|
||||||
let newRow = db.getRow(sql(
|
|
||||||
"INSERT INTO " & tableName(rec) &
|
|
||||||
" (" & mc.columns.join(",") & ") " &
|
|
||||||
" VALUES (" & mc.placeholders.join(",") & ") " &
|
|
||||||
" RETURNING *"), mc.values)
|
|
||||||
|
|
||||||
result = rowToModel(T, newRow)
|
|
||||||
|
|
||||||
proc updateRecord*[T](db: DbConn, rec: T): bool =
|
|
||||||
var mc = newMutateClauses()
|
|
||||||
populateMutateClauses(rec, false, mc)
|
|
||||||
|
|
||||||
let setClause = zip(mc.columns, mc.placeholders).mapIt(it.a & " = " & it.b).join(",")
|
|
||||||
let numRowsUpdated = db.execAffectedRows(sql(
|
|
||||||
"UPDATE " & tableName(rec) &
|
|
||||||
" SET " & setClause &
|
|
||||||
" WHERE id = ? "), mc.values.concat(@[$rec.id]))
|
|
||||||
|
|
||||||
return numRowsUpdated > 0;
|
|
||||||
|
|
||||||
template deleteRecord*(db: DbConn, modelType: type, id: typed): untyped =
|
|
||||||
db.tryExec(sql("DELETE FROM " & tableName(modelType) & " WHERE id = ?"), $id)
|
|
||||||
|
|
||||||
proc deleteRecord*[T](db: DbConn, rec: T): bool =
|
|
||||||
return db.tryExec(sql("DELETE FROM " & tableName(rec) & " WHERE id = ?"), $rec.id)
|
|
||||||
|
|
||||||
template getRecord*(db: DbConn, modelType: type, id: typed): untyped =
|
|
||||||
let row = db.getRow(sql(
|
|
||||||
"SELECT " & columnNamesForModel(modelType).join(",") &
|
|
||||||
" FROM " & tableName(modelType) &
|
|
||||||
" WHERE id = ?"), @[$id])
|
|
||||||
|
|
||||||
if row.allIt(it.len == 0):
|
|
||||||
raise newException(NotFoundError, "no record for id " & $id)
|
|
||||||
|
|
||||||
rowToModel(modelType, row)
|
|
||||||
|
|
||||||
template findRecordsWhere*(db: DbConn, modelType: type, whereClause: string, values: varargs[string, dbFormat]): untyped =
|
|
||||||
db.getAllRows(sql(
|
|
||||||
"SELECT " & columnNamesForModel(modelType).join(",") &
|
|
||||||
" FROM " & tableName(modelType) &
|
|
||||||
" WHERE " & whereClause), values)
|
|
||||||
.mapIt(rowToModel(modelType, it))
|
|
||||||
|
|
||||||
template getAllRecords*(db: DbConn, modelType: type): untyped =
|
|
||||||
db.getAllRows(sql(
|
|
||||||
"SELECT " & columnNamesForModel(modelType).join(",") &
|
|
||||||
" FROM " & tableName(modelType)))
|
|
||||||
.mapIt(rowToModel(modelType, it))
|
|
||||||
|
|
||||||
template findRecordsBy*(db: DbConn, modelType: type, lookups: seq[tuple[field: string, value: string]]): untyped =
|
|
||||||
db.getAllRows(sql(
|
|
||||||
"SELECT " & columnNamesForModel(modelType).join(",") &
|
|
||||||
" FROM " & tableName(modelType) &
|
|
||||||
" WHERE " & lookups.mapIt(it.field & " = ?").join(" AND ")),
|
|
||||||
lookups.mapIt(it.value))
|
|
||||||
.mapIt(rowToModel(modelType, it))
|
|
||||||
|
|
||||||
macro generateProcsForModels*(modelTypes: openarray[type]): untyped =
|
|
||||||
result = newStmtList()
|
|
||||||
|
|
||||||
for t in modelTypes:
|
|
||||||
let modelName = $(t.getType[1])
|
|
||||||
let getName = ident("get" & modelName)
|
|
||||||
let getAllName = ident("getAll" & modelName & "s")
|
|
||||||
let findWhereName = ident("find" & modelName & "sWhere")
|
|
||||||
let createName = ident("create" & modelName)
|
|
||||||
let updateName = ident("update" & modelName)
|
|
||||||
let deleteName = ident("delete" & modelName)
|
|
||||||
let idType = typeOfColumn(t, "id")
|
|
||||||
result.add quote do:
|
|
||||||
proc `getName`*(db: PMApiDb, id: `idType`): `t` = getRecord(db.conn, `t`, id)
|
|
||||||
proc `getAllName`*(db: PMApiDb): seq[`t`] = getAllRecords(db.conn, `t`)
|
|
||||||
proc `findWhereName`*(db: PMApiDb, whereClause: string, values: varargs[string, dbFormat]): seq[`t`] =
|
|
||||||
return findRecordsWhere(db.conn, `t`, whereClause, values)
|
|
||||||
proc `createName`*(db: PMApiDb, rec: `t`): `t` = createRecord(db.conn, rec)
|
|
||||||
proc `updateName`*(db: PMApiDb, rec: `t`): bool = updateRecord(db.conn, rec)
|
|
||||||
proc `deleteName`*(db: PMApiDb, rec: `t`): bool = deleteRecord(db.conn, rec)
|
|
||||||
proc `deleteName`*(db: PMApiDb, id: `idType`): bool = deleteRecord(db.conn, `t`, id)
|
|
||||||
|
|
||||||
macro generateLookup*(modelType: type, fields: seq[string]): untyped =
|
|
||||||
let fieldNames = fields[1].mapIt($it)
|
|
||||||
let procName = ident("find" & $modelType.getType[1] & "sBy" & fieldNames.mapIt(it.capitalize).join("And"))
|
|
||||||
|
|
||||||
# Create proc skeleton
|
|
||||||
result = quote do:
|
|
||||||
proc `procName`*(db: PMApiDb): seq[`modelType`] =
|
|
||||||
return findRecordsBy(db.conn, `modelType`)
|
|
||||||
|
|
||||||
var callParams = quote do: @[]
|
|
||||||
|
|
||||||
# Add dynamic parameters for the proc definition and inner proc call
|
|
||||||
for n in fieldNames:
|
|
||||||
let paramTuple = newNimNode(nnkPar)
|
|
||||||
paramTuple.add(newColonExpr(ident("field"), newLit(identNameToDb(n))))
|
|
||||||
paramTuple.add(newColonExpr(ident("value"), ident(n)))
|
|
||||||
|
|
||||||
result[3].add(newIdentDefs(ident(n), ident("string")))
|
|
||||||
callParams[1].add(paramTuple)
|
|
||||||
|
|
||||||
result[6][0][0].add(callParams)
|
|
||||||
|
|
||||||
macro generateProcsForFieldLookups*(modelsAndFields: openarray[tuple[t: type, fields: seq[string]]]): untyped =
|
|
||||||
result = newStmtList()
|
|
||||||
|
|
||||||
for i in modelsAndFields:
|
|
||||||
var modelType = i[1][0]
|
|
||||||
let fieldNames = i[1][1][1].mapIt($it)
|
|
||||||
|
|
||||||
let procName = ident("find" & $modelType & "sBy" & fieldNames.mapIt(it.capitalize).join("And"))
|
|
||||||
|
|
||||||
# Create proc skeleton
|
|
||||||
let procDefAST = quote do:
|
|
||||||
proc `procName`*(db: PMApiDb): seq[`modelType`] =
|
|
||||||
return findRecordsBy(db.conn, `modelType`)
|
|
||||||
|
|
||||||
var callParams = quote do: @[]
|
|
||||||
|
|
||||||
# Add dynamic parameters for the proc definition and inner proc call
|
|
||||||
for n in fieldNames:
|
|
||||||
let paramTuple = newNimNode(nnkPar)
|
|
||||||
paramTuple.add(newColonExpr(ident("field"), newLit(n)))
|
|
||||||
paramTuple.add(newColonExpr(ident("value"), ident(n)))
|
|
||||||
|
|
||||||
procDefAST[3].add(newIdentDefs(ident(n), ident("string")))
|
|
||||||
callParams[1].add(paramTuple)
|
|
||||||
|
|
||||||
procDefAST[6][0][0].add(callParams)
|
|
||||||
|
|
||||||
result.add procDefAST
|
|
@ -1,287 +0,0 @@
|
|||||||
import json, macros, options, sequtils, strutils, times, timeutils, unicode,
|
|
||||||
uuids
|
|
||||||
|
|
||||||
const UNDERSCORE_RUNE = "_".toRunes[0]
|
|
||||||
const PG_TIMESTAMP_FORMATS = [
|
|
||||||
"yyyy-MM-dd HH:mm:sszz",
|
|
||||||
"yyyy-MM-dd HH:mm:ss'.'fzz",
|
|
||||||
"yyyy-MM-dd HH:mm:ss'.'ffzz",
|
|
||||||
"yyyy-MM-dd HH:mm:ss'.'fffzz"
|
|
||||||
]
|
|
||||||
|
|
||||||
type
|
|
||||||
MutateClauses* = object
|
|
||||||
columns*: seq[string]
|
|
||||||
placeholders*: seq[string]
|
|
||||||
values*: seq[string]
|
|
||||||
|
|
||||||
# TODO: more complete implementation
|
|
||||||
# see https://github.com/blakeembrey/pluralize
|
|
||||||
proc pluralize(name: string): string =
|
|
||||||
if name[^2..^1] == "ey": return name[0..^3] & "ies"
|
|
||||||
if name[^1] == 'y': return name[0..^2] & "ies"
|
|
||||||
return name & "s"
|
|
||||||
|
|
||||||
macro modelName*(model: object): string =
|
|
||||||
return $model.getTypeInst
|
|
||||||
|
|
||||||
macro modelName*(modelType: type): string =
|
|
||||||
return $modelType.getType[1]
|
|
||||||
|
|
||||||
proc identNameToDb*(name: string): string =
|
|
||||||
let nameInRunes = name.toRunes
|
|
||||||
var prev: Rune
|
|
||||||
var resultRunes = newSeq[Rune]()
|
|
||||||
|
|
||||||
for cur in nameInRunes:
|
|
||||||
if resultRunes.len == 0:
|
|
||||||
resultRunes.add(toLower(cur))
|
|
||||||
elif isLower(prev) and isUpper(cur):
|
|
||||||
resultRunes.add(UNDERSCORE_RUNE)
|
|
||||||
resultRunes.add(toLower(cur))
|
|
||||||
else: resultRunes.add(toLower(cur))
|
|
||||||
|
|
||||||
prev = cur
|
|
||||||
|
|
||||||
return $resultRunes
|
|
||||||
|
|
||||||
proc dbNameToIdent*(name: string): string =
|
|
||||||
let parts = name.split("_")
|
|
||||||
return @[parts[0]].concat(parts[1..^1].mapIt(capitalize(it))).join("")
|
|
||||||
|
|
||||||
proc tableName*(modelType: type): string =
|
|
||||||
return pluralize(modelName(modelType).identNameToDb)
|
|
||||||
|
|
||||||
proc tableName*[T](rec: T): string =
|
|
||||||
return pluralize(modelName(rec).identNameToDb)
|
|
||||||
|
|
||||||
proc dbFormat*(s: string): string = return s
|
|
||||||
|
|
||||||
proc dbFormat*(dt: DateTime): string = return dt.formatIso8601
|
|
||||||
|
|
||||||
proc dbFormat*[T](list: seq[T]): string =
|
|
||||||
return "{" & list.mapIt(dbFormat(it)).join(",") & "}"
|
|
||||||
|
|
||||||
proc dbFormat*[T](item: T): string = return $item
|
|
||||||
|
|
||||||
type DbArrayParseState = enum
|
|
||||||
expectStart, inQuote, inVal, expectEnd
|
|
||||||
|
|
||||||
proc parsePGDatetime*(val: string): DateTime =
|
|
||||||
var errStr = ""
|
|
||||||
for df in PG_TIMESTAMP_FORMATS:
|
|
||||||
try: return val.parse(df)
|
|
||||||
except: errStr &= "\n" & getCurrentExceptionMsg()
|
|
||||||
raise newException(ValueError, "Cannot parse PG date. Tried:" & errStr)
|
|
||||||
|
|
||||||
proc parseDbArray*(val: string): seq[string] =
|
|
||||||
result = newSeq[string]()
|
|
||||||
|
|
||||||
var parseState = DbArrayParseState.expectStart
|
|
||||||
var curStr = ""
|
|
||||||
var idx = 1
|
|
||||||
var sawEscape = false
|
|
||||||
|
|
||||||
while idx < val.len - 1:
|
|
||||||
var curChar = val[idx]
|
|
||||||
idx += 1
|
|
||||||
|
|
||||||
case parseState:
|
|
||||||
|
|
||||||
of expectStart:
|
|
||||||
if curChar == ' ': continue
|
|
||||||
elif curChar == '"':
|
|
||||||
parseState = inQuote
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
parseState = inVal
|
|
||||||
|
|
||||||
of expectEnd:
|
|
||||||
if curChar == ' ': continue
|
|
||||||
elif curChar == ',':
|
|
||||||
result.add(curStr)
|
|
||||||
curStr = ""
|
|
||||||
parseState = expectStart
|
|
||||||
continue
|
|
||||||
|
|
||||||
of inQuote:
|
|
||||||
if curChar == '"' and not sawEscape:
|
|
||||||
parseState = expectEnd
|
|
||||||
continue
|
|
||||||
|
|
||||||
of inVal:
|
|
||||||
if curChar == '"' and not sawEscape:
|
|
||||||
raise newException(ValueError, "Invalid DB array value (cannot have '\"' in the middle of an unquoted string).")
|
|
||||||
elif curChar == ',':
|
|
||||||
result.add(curStr)
|
|
||||||
curStr = ""
|
|
||||||
parseState = expectStart
|
|
||||||
continue
|
|
||||||
|
|
||||||
# if we saw an escaped \", add just the ", otherwise add both
|
|
||||||
if sawEscape:
|
|
||||||
if curChar != '"': curStr.add('\\')
|
|
||||||
curStr.add(curChar)
|
|
||||||
sawEscape = false
|
|
||||||
|
|
||||||
elif curChar == '\\':
|
|
||||||
sawEscape = true
|
|
||||||
|
|
||||||
else: curStr.add(curChar)
|
|
||||||
|
|
||||||
if not (parseState == inQuote) and curStr.len > 0:
|
|
||||||
result.add(curStr)
|
|
||||||
|
|
||||||
proc createParseStmt*(t, value: NimNode): NimNode =
|
|
||||||
|
|
||||||
#echo "Creating parse statment for ", t.treeRepr
|
|
||||||
if t.typeKind == ntyObject:
|
|
||||||
|
|
||||||
if t.getType == UUID.getType:
|
|
||||||
result = quote do: parseUUID(`value`)
|
|
||||||
|
|
||||||
elif t.getType == DateTime.getType:
|
|
||||||
result = quote do: parsePGDatetime(`value`)
|
|
||||||
|
|
||||||
elif t.getTypeInst == Option.getType:
|
|
||||||
let innerType = t.getTypeImpl[2][0][0][1]
|
|
||||||
let parseStmt = createParseStmt(innerType, value)
|
|
||||||
result = quote do:
|
|
||||||
if `value`.len == 0: none[`innerType`]()
|
|
||||||
else: some(`parseStmt`)
|
|
||||||
|
|
||||||
else: error "Unknown value object type: " & $t.getTypeInst
|
|
||||||
|
|
||||||
elif t.typeKind == ntyRef:
|
|
||||||
|
|
||||||
if $t.getTypeInst == "JsonNode":
|
|
||||||
result = quote do: parseJson(`value`)
|
|
||||||
|
|
||||||
else:
|
|
||||||
error "Unknown ref type: " & $t.getTypeInst
|
|
||||||
|
|
||||||
elif t.typeKind == ntySequence:
|
|
||||||
let innerType = t[1]
|
|
||||||
|
|
||||||
let parseStmts = createParseStmt(innerType, ident("it"))
|
|
||||||
|
|
||||||
result = quote do: parseDbArray(`value`).mapIt(`parseStmts`)
|
|
||||||
|
|
||||||
elif t.typeKind == ntyString:
|
|
||||||
result = quote do: `value`
|
|
||||||
|
|
||||||
elif t.typeKind == ntyInt:
|
|
||||||
result = quote do: parseInt(`value`)
|
|
||||||
|
|
||||||
elif t.typeKind == ntyBool:
|
|
||||||
result = quote do: "true".startsWith(`value`.toLower)
|
|
||||||
|
|
||||||
else:
|
|
||||||
error "Unknown value type: " & $t.typeKind
|
|
||||||
|
|
||||||
template walkFieldDefs*(t: NimNode, body: untyped) =
|
|
||||||
let tTypeImpl = t.getTypeImpl
|
|
||||||
|
|
||||||
var nodeToItr: NimNode
|
|
||||||
if tTypeImpl.typeKind == ntyObject: nodeToItr = tTypeImpl[2]
|
|
||||||
elif tTypeImpl.typeKind == ntyTypeDesc: nodeToItr = tTypeImpl.getType[1].getType[2]
|
|
||||||
else: error $t & " is not an object or type desc (it's a " & $tTypeImpl.typeKind & ")."
|
|
||||||
|
|
||||||
for fieldDef {.inject.} in nodeToItr.children:
|
|
||||||
# ignore AST nodes that are not field definitions
|
|
||||||
if fieldDef.kind == nnkIdentDefs:
|
|
||||||
let fieldIdent {.inject.} = fieldDef[0]
|
|
||||||
let fieldType {.inject.} = fieldDef[1]
|
|
||||||
body
|
|
||||||
|
|
||||||
elif fieldDef.kind == nnkSym:
|
|
||||||
let fieldIdent {.inject.} = fieldDef
|
|
||||||
let fieldType {.inject.} = fieldDef.getType
|
|
||||||
body
|
|
||||||
|
|
||||||
macro columnNamesForModel*(modelType: typed): seq[string] =
|
|
||||||
var columnNames = newSeq[string]()
|
|
||||||
|
|
||||||
modelType.walkFieldDefs:
|
|
||||||
columnNames.add(identNameToDb($fieldIdent))
|
|
||||||
|
|
||||||
result = newLit(columnNames)
|
|
||||||
|
|
||||||
macro rowToModel*(modelType: typed, row: seq[string]): untyped =
|
|
||||||
|
|
||||||
# Create the object constructor AST node
|
|
||||||
result = newNimNode(nnkObjConstr).add(modelType)
|
|
||||||
|
|
||||||
# Create new colon expressions for each of the property initializations
|
|
||||||
var idx = 0
|
|
||||||
modelType.walkFieldDefs:
|
|
||||||
let itemLookup = quote do: `row`[`idx`]
|
|
||||||
result.add(newColonExpr(
|
|
||||||
fieldIdent,
|
|
||||||
createParseStmt(fieldType, itemLookup)))
|
|
||||||
idx += 1
|
|
||||||
|
|
||||||
macro listFields*(t: typed): untyped =
|
|
||||||
var fields: seq[tuple[n: string, t: string]] = @[]
|
|
||||||
t.walkFieldDefs:
|
|
||||||
if fieldDef.kind == nnkSym: fields.add((n: $fieldIdent, t: fieldType.repr))
|
|
||||||
else: fields.add((n: $fieldIdent, t: $fieldType))
|
|
||||||
|
|
||||||
result = newLit(fields)
|
|
||||||
|
|
||||||
proc typeOfColumn*(modelType: NimNode, colName: string): NimNode =
|
|
||||||
modelType.walkFieldDefs:
|
|
||||||
if $fieldIdent != colName: continue
|
|
||||||
|
|
||||||
if fieldType.typeKind == ntyObject:
|
|
||||||
|
|
||||||
if fieldType.getType == UUID.getType: return ident("UUID")
|
|
||||||
elif fieldType.getType == DateTime.getType: return ident("DateTime")
|
|
||||||
elif fieldType.getType == Option.getType: return ident("Option")
|
|
||||||
else: error "Unknown column type: " & $fieldType.getTypeInst
|
|
||||||
|
|
||||||
else: return fieldType
|
|
||||||
|
|
||||||
raise newException(Exception,
|
|
||||||
"model of type '" & $modelType & "' has no column named '" & colName & "'")
|
|
||||||
|
|
||||||
proc isZero(val: int): bool = return val == 0
|
|
||||||
|
|
||||||
macro populateMutateClauses*(t: typed, newRecord: bool, mc: var MutateClauses): untyped =
|
|
||||||
|
|
||||||
result = newStmtList()
|
|
||||||
|
|
||||||
# iterate over all the object's fields
|
|
||||||
t.walkFieldDefs:
|
|
||||||
|
|
||||||
# grab the field, it's string name, and it's type
|
|
||||||
let fieldName = $fieldIdent
|
|
||||||
|
|
||||||
# we do not update the ID, but we do check: if we're creating a new
|
|
||||||
# record, we should not have an existing ID
|
|
||||||
if fieldName == "id":
|
|
||||||
result.add quote do:
|
|
||||||
if `newRecord` and not `t`.id.isZero:
|
|
||||||
raise newException(
|
|
||||||
AssertionError,
|
|
||||||
"Trying to create a new record, but the record already has an ID (" & $(`t`.id) & ").")
|
|
||||||
|
|
||||||
# if we're looking at an optional field, add logic to check for presence
|
|
||||||
elif fieldType.kind == nnkBracketExpr and
|
|
||||||
fieldType.len > 0 and
|
|
||||||
fieldType[0] == Option.getType:
|
|
||||||
|
|
||||||
result.add quote do:
|
|
||||||
`mc`.columns.add(identNameToDb(`fieldName`))
|
|
||||||
if `t`.`fieldIdent`.isSome:
|
|
||||||
`mc`.placeholders.add("?")
|
|
||||||
`mc`.values.add(dbFormat(`t`.`fieldIdent`.get))
|
|
||||||
else:
|
|
||||||
`mc`.placeholders.add("NULL")
|
|
||||||
|
|
||||||
# otherwise assume we can convert and go ahead.
|
|
||||||
else:
|
|
||||||
result.add quote do:
|
|
||||||
`mc`.columns.add(identNameToDb(`fieldName`))
|
|
||||||
`mc`.placeholders.add("?")
|
|
||||||
`mc`.values.add(dbFormat(`t`.`fieldIdent`))
|
|
@ -28,7 +28,7 @@ type
|
|||||||
Measurement* = object
|
Measurement* = object
|
||||||
id*: UUID
|
id*: UUID
|
||||||
measureId*: UUID
|
measureId*: UUID
|
||||||
value*: int
|
value*: float
|
||||||
timestamp*: DateTime
|
timestamp*: DateTime
|
||||||
extData*: JsonNode
|
extData*: JsonNode
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
const PM_API_VERSION* = "0.5.0"
|
const PM_API_VERSION* = "0.8.0"
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
-- DOWN script for measure-value-is-numeric (20200216230431)
|
||||||
|
alter table "measurements" alter column "value" type integer;
|
@ -0,0 +1,2 @@
|
|||||||
|
-- UP script for measure-value-is-numeric (20200216230431)
|
||||||
|
alter table "measurements" alter column "value" type numeric;
|
@ -46,9 +46,6 @@ user to manage these without a password.
|
|||||||
pmapi ALL=NOPASSWD: /bin/systemctl stop personal_measure_api.dev.service
|
pmapi ALL=NOPASSWD: /bin/systemctl stop personal_measure_api.dev.service
|
||||||
pmapi ALL=NOPASSWD: /bin/systemctl start personal_measure_api.dev.service
|
pmapi ALL=NOPASSWD: /bin/systemctl start personal_measure_api.dev.service
|
||||||
|
|
||||||
two systemd
|
|
||||||
service definitions, one for
|
|
||||||
|
|
||||||
### Database
|
### Database
|
||||||
|
|
||||||
razgriz-db.jdb-labs.com RDS instance maintains databases for each environment:
|
razgriz-db.jdb-labs.com RDS instance maintains databases for each environment:
|
||||||
@ -60,17 +57,9 @@ razgriz-db.jdb-labs.com RDS instance maintains databases for each environment:
|
|||||||
CloudFront manages the routing of all of the external facing URLs.
|
CloudFront manages the routing of all of the external facing URLs.
|
||||||
|
|
||||||
https://pm.jdb-labs.com (CloudFront)
|
https://pm.jdb-labs.com (CloudFront)
|
||||||
├── /api/<path>
|
|
||||||
│ └── https://pmapi.jdb-labs.com/api/
|
|
||||||
│ ├── nginx:80 --> nim/jester:8280
|
|
||||||
│ └── razgriz-db: database personal_measure
|
|
||||||
└── s3://pm.jdb-labs.com/prod/webroot (static HTML)
|
└── s3://pm.jdb-labs.com/prod/webroot (static HTML)
|
||||||
|
|
||||||
https://pm-dev.jdb-labs.com (CloudFront)
|
https://pm-dev.jdb-labs.com (CloudFront)
|
||||||
├── /api/<path>
|
|
||||||
│ └── https://pmapi-dev.jdb-labs.com/api/
|
|
||||||
│ ├── nginx:80 --> nim/jester:8281
|
|
||||||
│ └── razgriz-db: database personal_measure_dev
|
|
||||||
└── s3://pm.jdb-labs.com/dev/webroot (static HTML)
|
└── s3://pm.jdb-labs.com/dev/webroot (static HTML)
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,15 +5,7 @@ variable "aws_region" {
|
|||||||
default = "us-west-2" # Oregon
|
default = "us-west-2" # Oregon
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "deploy_bucket_name" {
|
variable "app_root_url" {
|
||||||
description = "Name of the S3 bucket to store deployed artifacts, logs, etc."
|
description = "Name of the S3 bucket to store deployed artifacts, logs, etc."
|
||||||
default = "pm.jdb-labs.com"
|
default = "pm.jdb-labs.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
#### Provider Configuration
|
|
||||||
|
|
||||||
provider "aws" {
|
|
||||||
region = var.aws_region
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,28 @@
|
|||||||
|
provider "aws" {
|
||||||
|
region = var.aws_region
|
||||||
|
}
|
||||||
|
|
||||||
resource "aws_s3_bucket" "personal_measure" {
|
resource "aws_s3_bucket" "personal_measure" {
|
||||||
bucket = "${var.deploy_bucket_name}"
|
bucket = "${var.app_root_url}"
|
||||||
acl = "log-delivery-write"
|
acl = "log-delivery-write"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource "aws_dynamodb_table" "dynamodb_terraform-state-lock" {
|
||||||
|
name = "terraform-state-lock.${var.app_root_url}"
|
||||||
|
hash_key = "LockID"
|
||||||
|
read_capacity = 20
|
||||||
|
write_capacity = 20
|
||||||
|
|
||||||
|
attribute {
|
||||||
|
name = "LockID"
|
||||||
|
type = "S"
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = {
|
||||||
|
Name = "Terraform DynamoDB State Lock Table"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module "dev_env" {
|
module "dev_env" {
|
||||||
source = "./deployed_env"
|
source = "./deployed_env"
|
||||||
|
|
||||||
|
8
operations/terraform/terraform.tf
Normal file
8
operations/terraform/terraform.tf
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
terraform {
|
||||||
|
backend "s3" {
|
||||||
|
bucket = "pm.jdb-labs.com"
|
||||||
|
region = "us-west-2"
|
||||||
|
key = "terraform.tfstate"
|
||||||
|
dynamodb_table = "terraform-state-lock.pm.jdb-labs.com"
|
||||||
|
}
|
||||||
|
}
|
@ -1,547 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 4,
|
|
||||||
"terraform_version": "0.12.9",
|
|
||||||
"serial": 13,
|
|
||||||
"lineage": "07ea4679-dcfc-ec03-69c0-9f3b3df53386",
|
|
||||||
"outputs": {},
|
|
||||||
"resources": [
|
|
||||||
{
|
|
||||||
"module": "module.prod_env",
|
|
||||||
"mode": "data",
|
|
||||||
"type": "aws_iam_policy_document",
|
|
||||||
"name": "bucket_access_policy",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"id": "4164925389",
|
|
||||||
"json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM\"\n }\n }\n ]\n}",
|
|
||||||
"override_json": null,
|
|
||||||
"policy_id": null,
|
|
||||||
"source_json": null,
|
|
||||||
"statement": [
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"s3:GetObject"
|
|
||||||
],
|
|
||||||
"condition": [],
|
|
||||||
"effect": "Allow",
|
|
||||||
"not_actions": [],
|
|
||||||
"not_principals": [],
|
|
||||||
"not_resources": [],
|
|
||||||
"principals": [
|
|
||||||
{
|
|
||||||
"identifiers": [
|
|
||||||
"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM"
|
|
||||||
],
|
|
||||||
"type": "AWS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*"
|
|
||||||
],
|
|
||||||
"sid": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"s3:ListBucket"
|
|
||||||
],
|
|
||||||
"condition": [],
|
|
||||||
"effect": "Allow",
|
|
||||||
"not_actions": [],
|
|
||||||
"not_principals": [],
|
|
||||||
"not_resources": [],
|
|
||||||
"principals": [
|
|
||||||
{
|
|
||||||
"identifiers": [
|
|
||||||
"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM"
|
|
||||||
],
|
|
||||||
"type": "AWS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
"arn:aws:s3:::pm.jdb-labs.com"
|
|
||||||
],
|
|
||||||
"sid": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": "2012-10-17"
|
|
||||||
},
|
|
||||||
"depends_on": [
|
|
||||||
"aws_cloudfront_origin_access_identity.origin_access_identity"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module": "module.dev_env",
|
|
||||||
"mode": "data",
|
|
||||||
"type": "aws_iam_policy_document",
|
|
||||||
"name": "bucket_access_policy",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"id": "672870168",
|
|
||||||
"json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY\"\n }\n }\n ]\n}",
|
|
||||||
"override_json": null,
|
|
||||||
"policy_id": null,
|
|
||||||
"source_json": null,
|
|
||||||
"statement": [
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"s3:GetObject"
|
|
||||||
],
|
|
||||||
"condition": [],
|
|
||||||
"effect": "Allow",
|
|
||||||
"not_actions": [],
|
|
||||||
"not_principals": [],
|
|
||||||
"not_resources": [],
|
|
||||||
"principals": [
|
|
||||||
{
|
|
||||||
"identifiers": [
|
|
||||||
"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY"
|
|
||||||
],
|
|
||||||
"type": "AWS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*"
|
|
||||||
],
|
|
||||||
"sid": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"s3:ListBucket"
|
|
||||||
],
|
|
||||||
"condition": [],
|
|
||||||
"effect": "Allow",
|
|
||||||
"not_actions": [],
|
|
||||||
"not_principals": [],
|
|
||||||
"not_resources": [],
|
|
||||||
"principals": [
|
|
||||||
{
|
|
||||||
"identifiers": [
|
|
||||||
"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY"
|
|
||||||
],
|
|
||||||
"type": "AWS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
"arn:aws:s3:::pm.jdb-labs.com"
|
|
||||||
],
|
|
||||||
"sid": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": "2012-10-17"
|
|
||||||
},
|
|
||||||
"depends_on": [
|
|
||||||
"aws_cloudfront_origin_access_identity.origin_access_identity"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "data",
|
|
||||||
"type": "aws_iam_policy_document",
|
|
||||||
"name": "cloudfront_access_policy",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"id": "1534115699",
|
|
||||||
"json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM\"\n }\n }\n ]\n}",
|
|
||||||
"override_json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM\"\n }\n }\n ]\n}",
|
|
||||||
"policy_id": null,
|
|
||||||
"source_json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY\"\n }\n }\n ]\n}",
|
|
||||||
"statement": null,
|
|
||||||
"version": "2012-10-17"
|
|
||||||
},
|
|
||||||
"depends_on": [
|
|
||||||
"module.dev_env",
|
|
||||||
"module.prod_env"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module": "module.prod_env",
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_cloudfront_distribution",
|
|
||||||
"name": "s3_distribution",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 1,
|
|
||||||
"attributes": {
|
|
||||||
"active_trusted_signers": {
|
|
||||||
"enabled": "false",
|
|
||||||
"items.#": "0"
|
|
||||||
},
|
|
||||||
"aliases": [
|
|
||||||
"pm.jdb-labs.com"
|
|
||||||
],
|
|
||||||
"arn": "arn:aws:cloudfront::063932952339:distribution/E331OLEUZMJYX2",
|
|
||||||
"cache_behavior": [],
|
|
||||||
"caller_reference": "terraform-20190924171430991900000002",
|
|
||||||
"comment": "Personal Measure prod distribution.",
|
|
||||||
"custom_error_response": [
|
|
||||||
{
|
|
||||||
"error_caching_min_ttl": null,
|
|
||||||
"error_code": 404,
|
|
||||||
"response_code": 200,
|
|
||||||
"response_page_path": "/index.html"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_cache_behavior": [
|
|
||||||
{
|
|
||||||
"allowed_methods": [
|
|
||||||
"GET",
|
|
||||||
"HEAD",
|
|
||||||
"OPTIONS"
|
|
||||||
],
|
|
||||||
"cached_methods": [
|
|
||||||
"GET",
|
|
||||||
"HEAD",
|
|
||||||
"OPTIONS"
|
|
||||||
],
|
|
||||||
"compress": true,
|
|
||||||
"default_ttl": 31536000,
|
|
||||||
"field_level_encryption_id": "",
|
|
||||||
"forwarded_values": [
|
|
||||||
{
|
|
||||||
"cookies": [
|
|
||||||
{
|
|
||||||
"forward": "none",
|
|
||||||
"whitelisted_names": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"headers": null,
|
|
||||||
"query_string": false,
|
|
||||||
"query_string_cache_keys": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"lambda_function_association": [],
|
|
||||||
"max_ttl": 31536000,
|
|
||||||
"min_ttl": 0,
|
|
||||||
"smooth_streaming": false,
|
|
||||||
"target_origin_id": "S3-PersonalMeasure-prod",
|
|
||||||
"trusted_signers": null,
|
|
||||||
"viewer_protocol_policy": "redirect-to-https"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_root_object": "/index.html",
|
|
||||||
"domain_name": "d1pydbw1mwi6dq.cloudfront.net",
|
|
||||||
"enabled": true,
|
|
||||||
"etag": "E39Y9O0I859AQB",
|
|
||||||
"hosted_zone_id": "Z2FDTNDATAQYW2",
|
|
||||||
"http_version": "http2",
|
|
||||||
"id": "E331OLEUZMJYX2",
|
|
||||||
"in_progress_validation_batches": 0,
|
|
||||||
"is_ipv6_enabled": true,
|
|
||||||
"last_modified_time": "2019-09-24 17:14:34.861 +0000 UTC",
|
|
||||||
"logging_config": [
|
|
||||||
{
|
|
||||||
"bucket": "pm.jdb-labs.com.s3.amazonaws.com",
|
|
||||||
"include_cookies": false,
|
|
||||||
"prefix": "prod/logs/cloudfront"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ordered_cache_behavior": [],
|
|
||||||
"origin": [
|
|
||||||
{
|
|
||||||
"custom_header": [],
|
|
||||||
"custom_origin_config": [],
|
|
||||||
"domain_name": "pm.jdb-labs.com.s3.us-west-2.amazonaws.com",
|
|
||||||
"origin_id": "S3-PersonalMeasure-prod",
|
|
||||||
"origin_path": "/prod/webroot",
|
|
||||||
"s3_origin_config": [
|
|
||||||
{
|
|
||||||
"origin_access_identity": "origin-access-identity/cloudfront/EV7VQF8SH3HMM"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"origin_group": [],
|
|
||||||
"price_class": "PriceClass_100",
|
|
||||||
"restrictions": [
|
|
||||||
{
|
|
||||||
"geo_restriction": [
|
|
||||||
{
|
|
||||||
"locations": null,
|
|
||||||
"restriction_type": "none"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"retain_on_delete": false,
|
|
||||||
"status": "Deployed",
|
|
||||||
"tags": {
|
|
||||||
"Environment": "prod"
|
|
||||||
},
|
|
||||||
"viewer_certificate": [
|
|
||||||
{
|
|
||||||
"acm_certificate_arn": "arn:aws:acm:us-east-1:063932952339:certificate/48fe3ce0-4700-4eaa-b433-bb634f47934c",
|
|
||||||
"cloudfront_default_certificate": false,
|
|
||||||
"iam_certificate_id": "",
|
|
||||||
"minimum_protocol_version": "TLSv1",
|
|
||||||
"ssl_support_method": "sni-only"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"wait_for_deployment": true,
|
|
||||||
"web_acl_id": ""
|
|
||||||
},
|
|
||||||
"private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==",
|
|
||||||
"depends_on": [
|
|
||||||
"aws_cloudfront_origin_access_identity.origin_access_identity"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module": "module.dev_env",
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_cloudfront_distribution",
|
|
||||||
"name": "s3_distribution",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 1,
|
|
||||||
"attributes": {
|
|
||||||
"active_trusted_signers": {
|
|
||||||
"enabled": "false",
|
|
||||||
"items.#": "0"
|
|
||||||
},
|
|
||||||
"aliases": [
|
|
||||||
"pm-dev.jdb-labs.com"
|
|
||||||
],
|
|
||||||
"arn": "arn:aws:cloudfront::063932952339:distribution/EYDKNEMGBYXK6",
|
|
||||||
"cache_behavior": [],
|
|
||||||
"caller_reference": "terraform-20190924171430991900000001",
|
|
||||||
"comment": "Personal Measure dev distribution.",
|
|
||||||
"custom_error_response": [
|
|
||||||
{
|
|
||||||
"error_caching_min_ttl": null,
|
|
||||||
"error_code": 404,
|
|
||||||
"response_code": 200,
|
|
||||||
"response_page_path": "/index.html"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_cache_behavior": [
|
|
||||||
{
|
|
||||||
"allowed_methods": [
|
|
||||||
"GET",
|
|
||||||
"HEAD",
|
|
||||||
"OPTIONS"
|
|
||||||
],
|
|
||||||
"cached_methods": [
|
|
||||||
"GET",
|
|
||||||
"HEAD",
|
|
||||||
"OPTIONS"
|
|
||||||
],
|
|
||||||
"compress": true,
|
|
||||||
"default_ttl": 31536000,
|
|
||||||
"field_level_encryption_id": "",
|
|
||||||
"forwarded_values": [
|
|
||||||
{
|
|
||||||
"cookies": [
|
|
||||||
{
|
|
||||||
"forward": "none",
|
|
||||||
"whitelisted_names": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"headers": null,
|
|
||||||
"query_string": false,
|
|
||||||
"query_string_cache_keys": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"lambda_function_association": [],
|
|
||||||
"max_ttl": 31536000,
|
|
||||||
"min_ttl": 0,
|
|
||||||
"smooth_streaming": false,
|
|
||||||
"target_origin_id": "S3-PersonalMeasure-dev",
|
|
||||||
"trusted_signers": null,
|
|
||||||
"viewer_protocol_policy": "redirect-to-https"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_root_object": "/index.html",
|
|
||||||
"domain_name": "d2gk6d79ot5fv3.cloudfront.net",
|
|
||||||
"enabled": true,
|
|
||||||
"etag": "E1DN3CB5IQVST8",
|
|
||||||
"hosted_zone_id": "Z2FDTNDATAQYW2",
|
|
||||||
"http_version": "http2",
|
|
||||||
"id": "EYDKNEMGBYXK6",
|
|
||||||
"in_progress_validation_batches": 0,
|
|
||||||
"is_ipv6_enabled": true,
|
|
||||||
"last_modified_time": "2019-09-24 17:14:32.614 +0000 UTC",
|
|
||||||
"logging_config": [
|
|
||||||
{
|
|
||||||
"bucket": "pm.jdb-labs.com.s3.amazonaws.com",
|
|
||||||
"include_cookies": false,
|
|
||||||
"prefix": "dev/logs/cloudfront"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ordered_cache_behavior": [],
|
|
||||||
"origin": [
|
|
||||||
{
|
|
||||||
"custom_header": [],
|
|
||||||
"custom_origin_config": [],
|
|
||||||
"domain_name": "pm.jdb-labs.com.s3.us-west-2.amazonaws.com",
|
|
||||||
"origin_id": "S3-PersonalMeasure-dev",
|
|
||||||
"origin_path": "/dev/webroot",
|
|
||||||
"s3_origin_config": [
|
|
||||||
{
|
|
||||||
"origin_access_identity": "origin-access-identity/cloudfront/ENADNQSO0I1JY"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"origin_group": [],
|
|
||||||
"price_class": "PriceClass_100",
|
|
||||||
"restrictions": [
|
|
||||||
{
|
|
||||||
"geo_restriction": [
|
|
||||||
{
|
|
||||||
"locations": null,
|
|
||||||
"restriction_type": "none"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"retain_on_delete": false,
|
|
||||||
"status": "Deployed",
|
|
||||||
"tags": {
|
|
||||||
"Environment": "dev"
|
|
||||||
},
|
|
||||||
"viewer_certificate": [
|
|
||||||
{
|
|
||||||
"acm_certificate_arn": "arn:aws:acm:us-east-1:063932952339:certificate/48fe3ce0-4700-4eaa-b433-bb634f47934c",
|
|
||||||
"cloudfront_default_certificate": false,
|
|
||||||
"iam_certificate_id": "",
|
|
||||||
"minimum_protocol_version": "TLSv1",
|
|
||||||
"ssl_support_method": "sni-only"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"wait_for_deployment": true,
|
|
||||||
"web_acl_id": ""
|
|
||||||
},
|
|
||||||
"private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==",
|
|
||||||
"depends_on": [
|
|
||||||
"aws_cloudfront_origin_access_identity.origin_access_identity"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module": "module.prod_env",
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_cloudfront_origin_access_identity",
|
|
||||||
"name": "origin_access_identity",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"caller_reference": "terraform-20190924170615555500000002",
|
|
||||||
"cloudfront_access_identity_path": "origin-access-identity/cloudfront/EV7VQF8SH3HMM",
|
|
||||||
"comment": "OAI for Personal Measure {$var.environment} environment.",
|
|
||||||
"etag": "E1XJOGSBHHRD9K",
|
|
||||||
"iam_arn": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM",
|
|
||||||
"id": "EV7VQF8SH3HMM",
|
|
||||||
"s3_canonical_user_id": "3a882d18f05e2fa5a3cabc208bcb8c0e2143166b56c0b8442f5b8b405c203859a3f525afcabc2e52dd1c9799d883a166"
|
|
||||||
},
|
|
||||||
"private": "bnVsbA=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module": "module.dev_env",
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_cloudfront_origin_access_identity",
|
|
||||||
"name": "origin_access_identity",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"caller_reference": "terraform-20190924170615555100000001",
|
|
||||||
"cloudfront_access_identity_path": "origin-access-identity/cloudfront/ENADNQSO0I1JY",
|
|
||||||
"comment": "OAI for Personal Measure {$var.environment} environment.",
|
|
||||||
"etag": "E1K0T63S2F5CYR",
|
|
||||||
"iam_arn": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY",
|
|
||||||
"id": "ENADNQSO0I1JY",
|
|
||||||
"s3_canonical_user_id": "6e965a9a0e9034badac65e1ac223e048b6d1b934d146abd32c49634489959a5ee1252e34fb643cd222dde425f2abfcd4"
|
|
||||||
},
|
|
||||||
"private": "bnVsbA=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_s3_bucket",
|
|
||||||
"name": "personal_measure",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"acceleration_status": "",
|
|
||||||
"acl": "log-delivery-write",
|
|
||||||
"arn": "arn:aws:s3:::pm.jdb-labs.com",
|
|
||||||
"bucket": "pm.jdb-labs.com",
|
|
||||||
"bucket_domain_name": "pm.jdb-labs.com.s3.amazonaws.com",
|
|
||||||
"bucket_prefix": null,
|
|
||||||
"bucket_regional_domain_name": "pm.jdb-labs.com.s3.us-west-2.amazonaws.com",
|
|
||||||
"cors_rule": [],
|
|
||||||
"force_destroy": false,
|
|
||||||
"hosted_zone_id": "Z3BJ6K6RIION7M",
|
|
||||||
"id": "pm.jdb-labs.com",
|
|
||||||
"lifecycle_rule": [],
|
|
||||||
"logging": [],
|
|
||||||
"object_lock_configuration": [],
|
|
||||||
"policy": null,
|
|
||||||
"region": "us-west-2",
|
|
||||||
"replication_configuration": [],
|
|
||||||
"request_payer": "BucketOwner",
|
|
||||||
"server_side_encryption_configuration": [],
|
|
||||||
"tags": {},
|
|
||||||
"versioning": [
|
|
||||||
{
|
|
||||||
"enabled": false,
|
|
||||||
"mfa_delete": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"website": [],
|
|
||||||
"website_domain": null,
|
|
||||||
"website_endpoint": null
|
|
||||||
},
|
|
||||||
"private": "bnVsbA=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_s3_bucket_policy",
|
|
||||||
"name": "personal_measure",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"bucket": "pm.jdb-labs.com",
|
|
||||||
"id": "pm.jdb-labs.com",
|
|
||||||
"policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM\"\n }\n }\n ]\n}"
|
|
||||||
},
|
|
||||||
"private": "bnVsbA==",
|
|
||||||
"depends_on": [
|
|
||||||
"aws_s3_bucket.personal_measure",
|
|
||||||
"data.aws_iam_policy_document.cloudfront_access_policy"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,279 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 4,
|
|
||||||
"terraform_version": "0.12.9",
|
|
||||||
"serial": 9,
|
|
||||||
"lineage": "07ea4679-dcfc-ec03-69c0-9f3b3df53386",
|
|
||||||
"outputs": {},
|
|
||||||
"resources": [
|
|
||||||
{
|
|
||||||
"module": "module.prod_env",
|
|
||||||
"mode": "data",
|
|
||||||
"type": "aws_iam_policy_document",
|
|
||||||
"name": "bucket_access_policy",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"id": "1727217411",
|
|
||||||
"json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM\"\n }\n }\n ]\n}",
|
|
||||||
"override_json": null,
|
|
||||||
"policy_id": null,
|
|
||||||
"source_json": null,
|
|
||||||
"statement": [
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"s3:GetObject"
|
|
||||||
],
|
|
||||||
"condition": [],
|
|
||||||
"effect": "Allow",
|
|
||||||
"not_actions": [],
|
|
||||||
"not_principals": [],
|
|
||||||
"not_resources": [],
|
|
||||||
"principals": [
|
|
||||||
{
|
|
||||||
"identifiers": [
|
|
||||||
"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM"
|
|
||||||
],
|
|
||||||
"type": "AWS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*"
|
|
||||||
],
|
|
||||||
"sid": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"s3:ListBucket"
|
|
||||||
],
|
|
||||||
"condition": [],
|
|
||||||
"effect": "Allow",
|
|
||||||
"not_actions": [],
|
|
||||||
"not_principals": [],
|
|
||||||
"not_resources": [],
|
|
||||||
"principals": [
|
|
||||||
{
|
|
||||||
"identifiers": [
|
|
||||||
"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM"
|
|
||||||
],
|
|
||||||
"type": "AWS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
"arn:aws:s3:::pm.jdb-labs.com"
|
|
||||||
],
|
|
||||||
"sid": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": "2012-10-17"
|
|
||||||
},
|
|
||||||
"depends_on": [
|
|
||||||
"aws_cloudfront_origin_access_identity.origin_access_identity"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module": "module.dev_env",
|
|
||||||
"mode": "data",
|
|
||||||
"type": "aws_iam_policy_document",
|
|
||||||
"name": "bucket_access_policy",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"id": "3067586518",
|
|
||||||
"json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY\"\n }\n }\n ]\n}",
|
|
||||||
"override_json": null,
|
|
||||||
"policy_id": null,
|
|
||||||
"source_json": null,
|
|
||||||
"statement": [
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"s3:GetObject"
|
|
||||||
],
|
|
||||||
"condition": [],
|
|
||||||
"effect": "Allow",
|
|
||||||
"not_actions": [],
|
|
||||||
"not_principals": [],
|
|
||||||
"not_resources": [],
|
|
||||||
"principals": [
|
|
||||||
{
|
|
||||||
"identifiers": [
|
|
||||||
"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY"
|
|
||||||
],
|
|
||||||
"type": "AWS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*"
|
|
||||||
],
|
|
||||||
"sid": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"s3:ListBucket"
|
|
||||||
],
|
|
||||||
"condition": [],
|
|
||||||
"effect": "Allow",
|
|
||||||
"not_actions": [],
|
|
||||||
"not_principals": [],
|
|
||||||
"not_resources": [],
|
|
||||||
"principals": [
|
|
||||||
{
|
|
||||||
"identifiers": [
|
|
||||||
"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY"
|
|
||||||
],
|
|
||||||
"type": "AWS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
"arn:aws:s3:::pm.jdb-labs.com"
|
|
||||||
],
|
|
||||||
"sid": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": "2012-10-17"
|
|
||||||
},
|
|
||||||
"depends_on": [
|
|
||||||
"aws_cloudfront_origin_access_identity.origin_access_identity"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "data",
|
|
||||||
"type": "aws_iam_policy_document",
|
|
||||||
"name": "cloudfront_access_policy",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"id": "754132408",
|
|
||||||
"json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM\"\n }\n }\n ]\n}",
|
|
||||||
"override_json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM\"\n }\n }\n ]\n}",
|
|
||||||
"policy_id": null,
|
|
||||||
"source_json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY\"\n }\n }\n ]\n}",
|
|
||||||
"statement": null,
|
|
||||||
"version": "2012-10-17"
|
|
||||||
},
|
|
||||||
"depends_on": [
|
|
||||||
"module.dev_env",
|
|
||||||
"module.prod_env"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module": "module.prod_env",
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_cloudfront_origin_access_identity",
|
|
||||||
"name": "origin_access_identity",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"caller_reference": "terraform-20190924170615555500000002",
|
|
||||||
"cloudfront_access_identity_path": "origin-access-identity/cloudfront/EV7VQF8SH3HMM",
|
|
||||||
"comment": "OAI for Personal Measure {$var.environment} environment.",
|
|
||||||
"etag": "E1XJOGSBHHRD9K",
|
|
||||||
"iam_arn": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EV7VQF8SH3HMM",
|
|
||||||
"id": "EV7VQF8SH3HMM",
|
|
||||||
"s3_canonical_user_id": "3a882d18f05e2fa5a3cabc208bcb8c0e2143166b56c0b8442f5b8b405c203859a3f525afcabc2e52dd1c9799d883a166"
|
|
||||||
},
|
|
||||||
"private": "bnVsbA=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module": "module.dev_env",
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_cloudfront_origin_access_identity",
|
|
||||||
"name": "origin_access_identity",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"caller_reference": "terraform-20190924170615555100000001",
|
|
||||||
"cloudfront_access_identity_path": "origin-access-identity/cloudfront/ENADNQSO0I1JY",
|
|
||||||
"comment": "OAI for Personal Measure {$var.environment} environment.",
|
|
||||||
"etag": "E1K0T63S2F5CYR",
|
|
||||||
"iam_arn": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENADNQSO0I1JY",
|
|
||||||
"id": "ENADNQSO0I1JY",
|
|
||||||
"s3_canonical_user_id": "6e965a9a0e9034badac65e1ac223e048b6d1b934d146abd32c49634489959a5ee1252e34fb643cd222dde425f2abfcd4"
|
|
||||||
},
|
|
||||||
"private": "bnVsbA=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_s3_bucket",
|
|
||||||
"name": "personal_measure",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"acceleration_status": "",
|
|
||||||
"acl": "log-delivery-write",
|
|
||||||
"arn": "arn:aws:s3:::pm.jdb-labs.com",
|
|
||||||
"bucket": "pm.jdb-labs.com",
|
|
||||||
"bucket_domain_name": "pm.jdb-labs.com.s3.amazonaws.com",
|
|
||||||
"bucket_prefix": null,
|
|
||||||
"bucket_regional_domain_name": "pm.jdb-labs.com.s3.us-west-2.amazonaws.com",
|
|
||||||
"cors_rule": [],
|
|
||||||
"force_destroy": false,
|
|
||||||
"hosted_zone_id": "Z3BJ6K6RIION7M",
|
|
||||||
"id": "pm.jdb-labs.com",
|
|
||||||
"lifecycle_rule": [],
|
|
||||||
"logging": [],
|
|
||||||
"object_lock_configuration": [],
|
|
||||||
"policy": null,
|
|
||||||
"region": "us-west-2",
|
|
||||||
"replication_configuration": [],
|
|
||||||
"request_payer": "BucketOwner",
|
|
||||||
"server_side_encryption_configuration": [],
|
|
||||||
"tags": {},
|
|
||||||
"versioning": [
|
|
||||||
{
|
|
||||||
"enabled": false,
|
|
||||||
"mfa_delete": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"website": [],
|
|
||||||
"website_domain": null,
|
|
||||||
"website_endpoint": null
|
|
||||||
},
|
|
||||||
"private": "bnVsbA=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "aws_s3_bucket_policy",
|
|
||||||
"name": "personal_measure",
|
|
||||||
"provider": "provider.aws",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"bucket": "pm.jdb-labs.com",
|
|
||||||
"id": "pm.jdb-labs.com",
|
|
||||||
"policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/dev/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_ENADNQSO0I1JY\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com/prod/webroot/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM\"\n }\n },\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::pm.jdb-labs.com\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront_Origin_Access_Identity_EV7VQF8SH3HMM\"\n }\n }\n ]\n}"
|
|
||||||
},
|
|
||||||
"private": "bnVsbA==",
|
|
||||||
"depends_on": [
|
|
||||||
"aws_s3_bucket.personal_measure",
|
|
||||||
"data.aws_iam_policy_document.cloudfront_access_policy"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
63
operations/update-version.sh
Executable file
63
operations/update-version.sh
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Script to update the version number, commit the changes to the version files,
|
||||||
|
# and tag the new commit.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
origDir=$(pwd)
|
||||||
|
rootDir=$(git rev-parse --show-toplevel)
|
||||||
|
cd "$rootDir"
|
||||||
|
|
||||||
|
currentBranch=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
if [ "$currentBranch" != "develop" ]; then
|
||||||
|
printf "You are currently on the '%s' branch. Is this intended (yes/no)? " "$currentBranch"
|
||||||
|
read -r confirmation
|
||||||
|
|
||||||
|
if [ "$confirmation" != "yes" ]; then exit 1; fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
lastVersion=$(jq -r .version web/package.json)
|
||||||
|
printf "Last version: %s\n" "$lastVersion"
|
||||||
|
printf "New version: "
|
||||||
|
read -r newVersion
|
||||||
|
|
||||||
|
printf "New version will be \"%s\". Is this correct (yes/no)? " "$newVersion"
|
||||||
|
read -r confirmation
|
||||||
|
|
||||||
|
if [ "$confirmation" != "yes" ]; then
|
||||||
|
printf "\n"
|
||||||
|
"$origDir/$0"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf ">> Updating /web/package.json with \"version\": \"%s\"\n" "$newVersion"
|
||||||
|
printf "jq \".version = \\\"%s\\\"\" web/package.json > temp.json\n" "$newVersion"
|
||||||
|
jq ".version = \"${newVersion}\"" web/package.json > temp.json
|
||||||
|
printf "mv temp.json web/package.json\n"
|
||||||
|
mv temp.json web/package.json
|
||||||
|
|
||||||
|
printf ">> Updating /web/package-lock.json with \"version\": \"%s\"\n" "$newVersion"
|
||||||
|
printf "jq \".version = \\\"%s\\\"\" web/package-lock.json > temp.json\n" "$newVersion"
|
||||||
|
jq ".version = \"${newVersion}\"" web/package-lock.json > temp.json
|
||||||
|
printf "mv temp.json web/package-lock.json\n"
|
||||||
|
mv temp.json web/package-lock.json
|
||||||
|
|
||||||
|
printf ">> Updating /api/src/main/nim/personal_measure_apipkg/version.nim with PM_API_VERSION* = \"%s\"" "$newVersion"
|
||||||
|
printf "sed -i \"s/%s/%s/\" api/src/main/nim/personal_measure_apipkg/version.nim" "$lastVersion" "$newVersion"
|
||||||
|
sed -i "s/${lastVersion}/${newVersion}/" api/src/main/nim/personal_measure_apipkg/version.nim
|
||||||
|
|
||||||
|
printf ">> Updating /api/personal_measure_api.nimble with version = \"%s\"" "$newVersion"
|
||||||
|
printf "sed -i \"s/%s/%s/\" api/personal_measure_api.nimble" "$lastVersion" "$newVersion"
|
||||||
|
sed -i "s/${lastVersion}/${newVersion}/" api/personal_measure_api.nimble
|
||||||
|
|
||||||
|
printf ">> Committing new version.\n"
|
||||||
|
printf "git add web/package.json web/package-lock.json api/src/main/nim/personal_measure_apipkg/version.nim"
|
||||||
|
git add web/package.json web/package-lock.json api/src/main/nim/personal_measure_apipkg/version.nim api/personal_measure_api.nimble
|
||||||
|
printf "git commit -m \"Update package version to %s\"\n" "$newVersion"
|
||||||
|
git commit -m "Update package version to ${newVersion}"
|
||||||
|
|
||||||
|
printf ">> Tagging commit.\n"
|
||||||
|
printf "git tag -m \"Version %s\" \"%s\"\n" "$newVersion" "$newVersion"
|
||||||
|
git tag -m "Version ${newVersion}" "${newVersion}"
|
||||||
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
if [[ -z $TARGET_ENV ]]; then
|
|
||||||
echo "TARGET_ENV variable is not set."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
export $(grep -v '^#' .env.$TARGET_ENV | xargs )
|
|
||||||
"$@"
|
|
@ -1,3 +1,4 @@
|
|||||||
|
NODE_ENV=production
|
||||||
VUE_APP_PM_API_BASE=https://pmapi-dev.jdb-labs.com/v0
|
VUE_APP_PM_API_BASE=https://pmapi-dev.jdb-labs.com/v0
|
||||||
VUE_APP_LOG_LEVEL=TRACE
|
VUE_APP_LOG_LEVEL=INFO
|
||||||
VUE_APP_API_LOG_LEVEL=ERROR
|
VUE_APP_API_LOG_LEVEL=ERROR
|
@ -1 +0,0 @@
|
|||||||
../.env.prod
|
|
3
web/.env.production
Normal file
3
web/.env.production
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
VUE_APP_PM_API_BASE=https://pmapi.jdb-labs.com/v0
|
||||||
|
VUE_APP_LOG_LEVEL=INFO
|
||||||
|
VUE_APP_API_LOG_LEVEL=ERROR
|
20
web/Makefile
20
web/Makefile
@ -1,23 +1,5 @@
|
|||||||
API_LOG_LEVEL='WARN'
|
|
||||||
LOG_LEVEL='TRACE'
|
|
||||||
|
|
||||||
build-dev:
|
|
||||||
npm run build-dev
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
npm run build
|
npm run build-${TARGET_ENV}
|
||||||
|
|
||||||
serve:
|
serve:
|
||||||
VUE_APP_PM_API_BASE=/api \
|
|
||||||
VUE_APP_API_LOG_LEVEL=${API_LOG_LEVEL} \
|
|
||||||
VUE_APP_LOG_LEVEL=${LOG_LEVEL} \
|
|
||||||
npm run serve
|
npm run serve
|
||||||
|
|
||||||
serve-dev: build-dev
|
|
||||||
(cd dist && npx live-server . --port=8080 --entry-file=index.html --proxy=/api:http://localhost:8081/api --no-browser)
|
|
||||||
|
|
||||||
serve-ssl: build-dev
|
|
||||||
(cd dist && \
|
|
||||||
(local-ssl-proxy --source=8443 --target=8080 & \
|
|
||||||
echo `pwd` && \
|
|
||||||
npx live-server . --port=8080 --entry-file=index.html --proxy=/api:http://localhost:8081/api --no-browser))
|
|
||||||
|
5405
web/package-lock.json
generated
5405
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,61 +1,61 @@
|
|||||||
{
|
{
|
||||||
"name": "personal-measure-web",
|
"name": "personal-measure-web",
|
||||||
"version": "0.5.0",
|
"version": "0.8.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "vue-cli-service build --mode production",
|
"build-prod": "vue-cli-service build --mode production",
|
||||||
"build-dev": "vue-cli-service build --mode development",
|
"build-dev": "vue-cli-service build --mode development",
|
||||||
"lint": "vue-cli-service lint",
|
"lint": "vue-cli-service lint",
|
||||||
"test:unit": "vue-cli-service test:unit"
|
"test:unit": "vue-cli-service test:unit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.15",
|
"@fortawesome/fontawesome-svg-core": "^1.2.27",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.7.2",
|
"@fortawesome/free-solid-svg-icons": "^5.12.1",
|
||||||
"@fortawesome/vue-fontawesome": "^0.1.5",
|
"@fortawesome/vue-fontawesome": "^0.1.9",
|
||||||
"@types/js-cookie": "^2.2.1",
|
"@types/js-cookie": "^2.2.4",
|
||||||
"@types/jwt-decode": "^2.2.1",
|
"@types/jwt-decode": "^2.2.1",
|
||||||
"@types/lodash.assign": "^4.2.6",
|
"@types/lodash.assign": "^4.2.6",
|
||||||
"@types/lodash.findindex": "^4.6.6",
|
"@types/lodash.findindex": "^4.6.6",
|
||||||
"@types/lodash.merge": "^4.6.5",
|
"@types/lodash.merge": "^4.6.6",
|
||||||
"apexcharts": "^3.6.5",
|
"apexcharts": "^3.15.6",
|
||||||
"axios": "^0.18.1",
|
"axios": "^0.18.1",
|
||||||
"js-cookie": "^2.2.0",
|
"js-cookie": "^2.2.1",
|
||||||
"jwt-decode": "^2.2.0",
|
"jwt-decode": "^2.2.0",
|
||||||
"keen-ui": "^1.1.2",
|
"keen-ui": "^1.2.1",
|
||||||
"lodash.assign": "^4.2.0",
|
"lodash.assign": "^4.2.0",
|
||||||
"lodash.findindex": "^4.6.0",
|
"lodash.findindex": "^4.6.0",
|
||||||
"lodash.keyby": "^4.6.0",
|
"lodash.keyby": "^4.6.0",
|
||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"register-service-worker": "^1.5.2",
|
"register-service-worker": "^1.5.2",
|
||||||
"vue": "^2.6.6",
|
"vue": "^2.6.11",
|
||||||
"vue-apexcharts": "^1.3.2",
|
"vue-apexcharts": "^1.5.2",
|
||||||
"vue-class-component": "^6.0.0",
|
"vue-class-component": "^6.0.0",
|
||||||
"vue-property-decorator": "^7.0.0",
|
"vue-property-decorator": "^7.0.0",
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.1.5",
|
||||||
"vuejs-smart-table": "0.0.3",
|
"vuejs-smart-table": "0.0.3",
|
||||||
"vuex": "^3.0.1",
|
"vuex": "^3.1.2",
|
||||||
"vuex-module-decorators": "^0.9.8"
|
"vuex-module-decorators": "^0.9.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^23.1.4",
|
"@types/jest": "^23.1.4",
|
||||||
"@types/lodash.keyby": "^4.6.6",
|
"@types/lodash.keyby": "^4.6.6",
|
||||||
"@vue/cli-plugin-babel": "^3.4.0",
|
"@vue/cli-plugin-babel": "^3.12.1",
|
||||||
"@vue/cli-plugin-pwa": "^3.4.0",
|
"@vue/cli-plugin-pwa": "^3.12.1",
|
||||||
"@vue/cli-plugin-typescript": "^3.4.0",
|
"@vue/cli-plugin-typescript": "^3.12.1",
|
||||||
"@vue/cli-plugin-unit-jest": "^3.7.0",
|
"@vue/cli-plugin-unit-jest": "^3.12.1",
|
||||||
"@vue/cli-service": "^3.5.3",
|
"@vue/cli-service": "^3.12.1",
|
||||||
"@vue/test-utils": "^1.0.0-beta.20",
|
"@vue/test-utils": "^1.0.0-beta.31",
|
||||||
"babel-core": "7.0.0-bridge.0",
|
"babel-core": "7.0.0-bridge.0",
|
||||||
"lint-staged": "^8.1.0",
|
"lint-staged": "^8.2.1",
|
||||||
"live-server": "^1.2.1",
|
"live-server": "^1.2.1",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^4.13.1",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.3.1",
|
||||||
"ts-jest": "^23.0.0",
|
"ts-jest": "^23.0.0",
|
||||||
"typescript": "^3.0.0",
|
"typescript": "^3.7.5",
|
||||||
"vue-cli-plugin-webpack-bundle-analyzer": "^1.3.0",
|
"vue-cli-plugin-webpack-bundle-analyzer": "^1.4.0",
|
||||||
"vue-template-compiler": "^2.5.21"
|
"vue-template-compiler": "^2.6.11"
|
||||||
},
|
},
|
||||||
"gitHooks": {
|
"gitHooks": {
|
||||||
"pre-commit": "lint-staged"
|
"pre-commit": "lint-staged"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div id="app">
|
<div id="app">
|
||||||
<NavBar></NavBar>
|
<NavBar></NavBar>
|
||||||
<router-view class=main />
|
<router-view class=main />
|
||||||
|
<span id="personal-measure-version" hidden>{{ version }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" src="./app.ts"></script>
|
<script lang="ts" src="./app.ts"></script>
|
||||||
|
@ -15,18 +15,21 @@ export class SimpleDetails extends Vue {
|
|||||||
// private newMeasurement;
|
// private newMeasurement;
|
||||||
private moment = moment;
|
private moment = moment;
|
||||||
private chartOptions = {
|
private chartOptions = {
|
||||||
|
markers: { size: 6 },
|
||||||
noData: { text: 'no data',
|
noData: { text: 'no data',
|
||||||
style: { fontSize: '18px' } },
|
style: { fontSize: '18px' } },
|
||||||
stroke: { curve: 'smooth' },
|
stroke: { curve: 'straight' },
|
||||||
xaxis: { type: 'datetime' }
|
xaxis: { type: 'datetime' }
|
||||||
};
|
};
|
||||||
|
|
||||||
private get measurementChartData(): ApexAxisChartSeries {
|
private get measurementChartData(): ApexAxisChartSeries {
|
||||||
const measurementData = this.measurements || [];
|
const measurementData = this.measurements.slice() || [];
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
name: this.measure.name,
|
name: this.measure.name,
|
||||||
data: measurementData.map((m) => ({ x: m.timestamp.toISOString(), y: m.value }))
|
data: measurementData
|
||||||
|
.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())
|
||||||
|
.map((m) => ({ x: m.timestamp.toISOString(), y: m.value }))
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="measure.config.isVisible" class="measure-summary" :data-name="'measure-' + measure.slug">
|
<div v-if="measure.config.isVisible" v-bind:key="measure.slug" class="measure-summary" :data-name="'measure-' + measure.slug">
|
||||||
<h2><router-link
|
<h2><router-link
|
||||||
:to="'/measures/' + measure.slug">
|
:to="'/measures/' + measure.slug">
|
||||||
{{measure.name}}</router-link></h2>
|
{{measure.name}}</router-link></h2>
|
||||||
|
@ -9,18 +9,20 @@ export class SimpleSummaryGraph extends Vue {
|
|||||||
private chartOptions = {
|
private chartOptions = {
|
||||||
chart: { sparkline: { enabled: true } },
|
chart: { sparkline: { enabled: true } },
|
||||||
grid: { padding: { top: 20 }},
|
grid: { padding: { top: 20 }},
|
||||||
stroke: { curve: 'smooth' },
|
stroke: { curve: 'straight' },
|
||||||
noData: { text: 'no data',
|
noData: { text: 'no data',
|
||||||
style: { fontSize: '18px' } },
|
style: { fontSize: '18px' } },
|
||||||
xaxis: { type: 'datetime' }
|
xaxis: { type: 'datetime' }
|
||||||
};
|
};
|
||||||
|
|
||||||
private get measurementData(): ApexAxisChartSeries {
|
private get measurementData(): ApexAxisChartSeries {
|
||||||
const measurementData = this.measurements || [];
|
const measurementData = this.measurements.slice() || [];
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
name: this.measure.name,
|
name: this.measure.name,
|
||||||
data: measurementData.map((m) => ({ x: m.timestamp.toISOString(), y: m.value }))
|
data: measurementData
|
||||||
|
.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())
|
||||||
|
.map((m) => ({ x: m.timestamp.toISOString(), y: m.value }))
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for=measurementValue>{{measure.name}}</label>
|
<label for=measurementValue>{{measure.name}}</label>
|
||||||
<input required type=number v-model=value.value :disabled=disabled />
|
<input name=measurementValue required type=number step=any v-model.number=value.value :disabled=disabled />
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</template>
|
</template>
|
||||||
|
@ -5,7 +5,7 @@ import { Measure, MeasureConfig, MeasureType, Measurement, MeasurementMeta } fro
|
|||||||
export class SimpleEntry extends Vue {
|
export class SimpleEntry extends Vue {
|
||||||
@Prop() public measure!: Measure<MeasureConfig>;
|
@Prop() public measure!: Measure<MeasureConfig>;
|
||||||
@Prop() public value!: Measurement<MeasurementMeta>;
|
@Prop() public value!: Measurement<MeasurementMeta>;
|
||||||
@Prop() public disabled: boolean = false;
|
@Prop() public disabled!: boolean;
|
||||||
private editTimestamp: boolean = false;
|
private editTimestamp: boolean = false;
|
||||||
|
|
||||||
@Watch('value', { immediate: true, deep: true })
|
@Watch('value', { immediate: true, deep: true })
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { LogLevel } from './log-message';
|
import { LogLevel } from './log-message';
|
||||||
import Logger from './logger';
|
import Logger from './logger';
|
||||||
import { default as Axios, AxiosInstance } from 'axios';
|
|
||||||
|
|
||||||
const ROOT_LOGGER_NAME = 'ROOT';
|
const ROOT_LOGGER_NAME = 'ROOT';
|
||||||
|
|
||||||
@ -8,7 +7,6 @@ const ROOT_LOGGER_NAME = 'ROOT';
|
|||||||
export class LogService {
|
export class LogService {
|
||||||
|
|
||||||
private loggers: { [key: string]: Logger };
|
private loggers: { [key: string]: Logger };
|
||||||
private http: AxiosInstance = Axios.create();
|
|
||||||
|
|
||||||
public get ROOT_LOGGER() {
|
public get ROOT_LOGGER() {
|
||||||
return this.loggers[ROOT_LOGGER_NAME];
|
return this.loggers[ROOT_LOGGER_NAME];
|
||||||
|
@ -32,7 +32,7 @@ export class AuthStoreModule extends VuexModule {
|
|||||||
// this should be guaranteed by the server (redirect HTTP -> HTTPS)
|
// this should be guaranteed by the server (redirect HTTP -> HTTPS)
|
||||||
// but we'll do a sanity check just to make sure.
|
// but we'll do a sanity check just to make sure.
|
||||||
if (window.location.protocol === 'https:' ||
|
if (window.location.protocol === 'https:' ||
|
||||||
process.env.NODE_ENV === 'development') { // allow in dev
|
process.env.NODE_ENV === 'development') { // allow http in dev
|
||||||
localStorage.setItem(SESSION_KEY, authToken);
|
localStorage.setItem(SESSION_KEY, authToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ export class MeasurementStoreModule extends VuexModule {
|
|||||||
const newMeasurements = existing.slice();
|
const newMeasurements = existing.slice();
|
||||||
|
|
||||||
const index = findIndex(existing, { id: measurement.id });
|
const index = findIndex(existing, { id: measurement.id });
|
||||||
if (index > 0) { newMeasurements.push(measurement); }
|
if (index < 0) { newMeasurements.push(measurement); }
|
||||||
else { newMeasurements[index] = measurement; }
|
else { newMeasurements[index] = measurement; }
|
||||||
this.measurements = assign({}, this.measurements, { [measure.id]: newMeasurements });
|
this.measurements = assign({}, this.measurements, { [measure.id]: newMeasurements });
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
.user-account {
|
.user-account {
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
section {
|
section {
|
||||||
margin-top: 1rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,7 @@ const VERSION = {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
devServer: {
|
devServer: {
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/v0': { target: 'http://localhost:8081' }
|
||||||
pathRewrite: { '^/api': '/v0' },
|
|
||||||
target: 'http://localhost:8081'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
disableHostCheck: true
|
disableHostCheck: true
|
||||||
|
Reference in New Issue
Block a user