Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
christian-stauffer authored Sep 19, 2023
0 parents commit 7bc59c9
Show file tree
Hide file tree
Showing 46 changed files with 3,513 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/code-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Code Analysis

on:
workflow_dispatch:
pull_request:
types:
- opened
- synchronize
branches:
- master
schedule:
- cron: '0 0 * * *' # Runs the job at 00:00 UTC every day

jobs:
app-integration-test:
uses: eliona-smart-building-assistant/app-integration-tests/.github/workflows/code-analysis.yml@main
secrets: inherit
17 changes: 17 additions & 0 deletions .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Integration Test

on:
workflow_dispatch:
pull_request:
types:
- opened
- synchronize
branches:
- master
schedule:
- cron: '0 0 * * *' # Runs the job at 00:00 UTC every day

jobs:
app-integration-test:
uses: eliona-smart-building-assistant/app-integration-tests/.github/workflows/app-integration-test.yml@main
secrets: inherit
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.iml
.idea/**
apiserver/.openapi-generator/**
apiserver/api/**
apiserver/*_service.go
40 changes: 40 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This file is part of the eliona project.
# Copyright © 2022 LEICOM iTEC AG. All Rights Reserved.
# ______ _ _
# | ____| (_)
# | |__ | |_ ___ _ __ __ _
# | __| | | |/ _ \| '_ \ / _` |
# | |____| | | (_) | | | | (_| |
# |______|_|_|\___/|_| |_|\__,_|
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

FROM eliona/base-golang:latest-1-alpine AS build

RUN apk add git

WORKDIR /
COPY . ./

RUN go mod download
RUN go build -o ../app

RUN DATE=$(date) && \
GIT_COMMIT=$(git rev-list -1 HEAD) && \
go build -ldflags "-X 'template/apiservices.BuildTimestamp=$DATE' -X 'template/apiservices.GitCommit=$GIT_COMMIT'" -o ../app

FROM eliona/base-alpine:latest-3.17 AS target

COPY --from=build /app ./
COPY conf/*.sql ./conf/
# COPY eliona/*.json ./eliona/
COPY openapi.yaml ./

ENV APPNAME=template

ENV TZ=Europe/Zurich
CMD [ "/app" ]
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 Leicom ITEC AG

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
81 changes: 81 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# App Template

This template is a part of the Eliona App SDK. It can be used to create an app stub for an Eliona environment.

## Configuration

The app needs environment variables and database tables for configuration. To edit the database tables the app provides an own API access.


### Registration in Eliona ###

To start and initialize an app in an Eliona environment, the app has to be registered in Eliona. For this, entries in database tables `public.eliona_app` and `public.eliona_store` are necessary.

This initialization can be handled by the `reset.sql` script.


### Environment variables

<mark>Todo: Describe further environment variables tables the app needs for configuration</mark>


- `APPNAME`: must be set to `template`. Some resources use this name to identify the app inside an Eliona environment.

- `CONNECTION_STRING`: configures the [Eliona database](https://github.com/eliona-smart-building-assistant/go-eliona/tree/main/db). Otherwise, the app can't be initialized and started. (e.g. `postgres://user:pass@localhost:5432/iot`)

- `API_ENDPOINT`: configures the endpoint to access the [Eliona API v2](https://github.com/eliona-smart-building-assistant/eliona-api). Otherwise, the app can't be initialized and started. (e.g. `http://api-v2:3000/v2`)

- `API_TOKEN`: defines the secret to authenticate the app and access the Eliona API.

- `API_SERVER_PORT`(optional): define the port the API server listens. The default value is Port `3000`. <mark>Todo: Decide if the app needs its own API. If so, an API server have to implemented and the port have to be configurable.</mark>

- `LOG_LEVEL`(optional): defines the minimum level that should be [logged](https://github.com/eliona-smart-building-assistant/go-utils/blob/main/log/README.md). The default level is `info`.

### Database tables ###

<mark>Todo: Describe the database objects the app needs for configuration</mark>

<mark>Todo: Decide if the app uses its own data and which data should be accessible from outside the app. This is always the case with configuration data. If so, the app needs its own API server to provide access to this data. To define the API use an openapi.yaml file and generators to build the server stub.</mark>

The app requires configuration data that remains in the database. To do this, the app creates its own database schema `template` during initialization. To modify and handle the configuration data the app provides an API access. Have a look at the [API specification](https://eliona-smart-building-assistant.github.io/open-api-docs/?https://raw.githubusercontent.com/eliona-smart-building-assistant/app-template/develop/openapi.yaml) how the configuration tables should be used.

- `template.example_table`: <mark>Todo: Describe the database table in short.</mark>

**Generation**: to generate access method to database see Generation section below.


## References

### App API ###

The app provides its own API to access configuration data and other functions. The full description of the API is defined in the `openapi.yaml` OpenAPI definition file.

- [API Reference](https://eliona-smart-building-assistant.github.io/open-api-docs/?https://raw.githubusercontent.com/eliona-smart-building-assistant/app-template/develop/openapi.yaml) shows Details of the API

**Generation**: to generate api server stub see Generation section below.


### Eliona ###

<mark>Todo: Describe all the data the app writes to eliona</mark>


## Tools

### Generate API server stub ###

For the API server the [OpenAPI Generator](https://openapi-generator.tech/docs/generators/openapi-yaml) for go-server is used to generate a server stub. The easiest way to generate the server files is to use one of the predefined generation script which use the OpenAPI Generator Docker image.

```
.\generate-api-server.cmd # Windows
./generate-api-server.sh # Linux
```

### Generate Database access ###

For the database access [SQLBoiler](https://github.com/volatiletech/sqlboiler) is used. The easiest way to generate the database files is to use one of the predefined generation script which use the SQLBoiler implementation. Please note that the database connection in the `sqlboiler.toml` file have to be configured.

```
.\generate-db.cmd # Windows
./generate-db.sh # Linux
```
9 changes: 9 additions & 0 deletions apiserver/.openapi-generator-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# If the API changes please remove these lines and merge the generated files with the existing ones.

api/**
README.md
64 changes: 64 additions & 0 deletions apiserver/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* App template API
*
* API to access and configure the app template
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/

package apiserver

import (
"context"
"net/http"
)

// ConfigurationApiRouter defines the required methods for binding the api requests to a responses for the ConfigurationApi
// The ConfigurationApiRouter implementation should parse necessary information from the http request,
// pass the data to a ConfigurationApiServicer to perform the required actions, then write the service results to the http response.
type ConfigurationApiRouter interface {
GetConfigurations(http.ResponseWriter, *http.Request)
PostConfiguration(http.ResponseWriter, *http.Request)
}

// CustomizationApiRouter defines the required methods for binding the api requests to a responses for the CustomizationApi
// The CustomizationApiRouter implementation should parse necessary information from the http request,
// pass the data to a CustomizationApiServicer to perform the required actions, then write the service results to the http response.
type CustomizationApiRouter interface {
GetDashboardTemplateByName(http.ResponseWriter, *http.Request)
}

// VersionApiRouter defines the required methods for binding the api requests to a responses for the VersionApi
// The VersionApiRouter implementation should parse necessary information from the http request,
// pass the data to a VersionApiServicer to perform the required actions, then write the service results to the http response.
type VersionApiRouter interface {
GetOpenAPI(http.ResponseWriter, *http.Request)
GetVersion(http.ResponseWriter, *http.Request)
}

// ConfigurationApiServicer defines the api actions for the ConfigurationApi service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type ConfigurationApiServicer interface {
GetConfigurations(context.Context) (ImplResponse, error)
PostConfiguration(context.Context, Configuration) (ImplResponse, error)
}

// CustomizationApiServicer defines the api actions for the CustomizationApi service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type CustomizationApiServicer interface {
GetDashboardTemplateByName(context.Context, string, string) (ImplResponse, error)
}

// VersionApiServicer defines the api actions for the VersionApi service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type VersionApiServicer interface {
GetOpenAPI(context.Context) (ImplResponse, error)
GetVersion(context.Context) (ImplResponse, error)
}
101 changes: 101 additions & 0 deletions apiserver/api_configuration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* App template API
*
* API to access and configure the app template
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/

package apiserver

import (
"encoding/json"
"net/http"
"strings"
)

// ConfigurationApiController binds http requests to an api service and writes the service results to the http response
type ConfigurationApiController struct {
service ConfigurationApiServicer
errorHandler ErrorHandler
}

// ConfigurationApiOption for how the controller is set up.
type ConfigurationApiOption func(*ConfigurationApiController)

// WithConfigurationApiErrorHandler inject ErrorHandler into controller
func WithConfigurationApiErrorHandler(h ErrorHandler) ConfigurationApiOption {
return func(c *ConfigurationApiController) {
c.errorHandler = h
}
}

// NewConfigurationApiController creates a default api controller
func NewConfigurationApiController(s ConfigurationApiServicer, opts ...ConfigurationApiOption) Router {
controller := &ConfigurationApiController{
service: s,
errorHandler: DefaultErrorHandler,
}

for _, opt := range opts {
opt(controller)
}

return controller
}

// Routes returns all the api routes for the ConfigurationApiController
func (c *ConfigurationApiController) Routes() Routes {
return Routes{
{
"GetConfigurations",
strings.ToUpper("Get"),
"/v1/configurations",
c.GetConfigurations,
},
{
"PostConfiguration",
strings.ToUpper("Post"),
"/v1/configurations",
c.PostConfiguration,
},
}
}

// GetConfigurations - Get configurations
func (c *ConfigurationApiController) GetConfigurations(w http.ResponseWriter, r *http.Request) {
result, err := c.service.GetConfigurations(r.Context())
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)

}

// PostConfiguration - Creates a configuration
func (c *ConfigurationApiController) PostConfiguration(w http.ResponseWriter, r *http.Request) {
configurationParam := Configuration{}
d := json.NewDecoder(r.Body)
d.DisallowUnknownFields()
if err := d.Decode(&configurationParam); err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
if err := AssertConfigurationRequired(configurationParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
result, err := c.service.PostConfiguration(r.Context(), configurationParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)

}
Loading

0 comments on commit 7bc59c9

Please sign in to comment.