merge eva repos into single repository

This commit is contained in:
gidsi 2018-04-20 18:08:55 +02:00
commit 200dd620ae
52 changed files with 2281 additions and 0 deletions

2
backend/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
eva-backend
.idea

15
backend/Dockerfile Normal file
View file

@ -0,0 +1,15 @@
FROM golang:alpine as builder
RUN apk --no-cache add git
WORKDIR /go/src/app
COPY . .
RUN go get -d -v ./...
RUN go install -v ./...
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /go/bin/app .
COPY config.yaml config.yaml
EXPOSE 8080
CMD ["./app", "-shared_secret=$SHARED_SECRET"]

15
backend/README.md Normal file
View file

@ -0,0 +1,15 @@
eva-backend
===========
See yaml file for database config
```bash
go get
go install
SHARED_SECRET=foo eva-backend
```
SpaceAPI extensions
===================
* Key `ext_ccc` describes Chaos Computer Club relation status (Example values: `"chaostreff"` or `"erfa"`)

47
backend/calendar.go Normal file
View file

@ -0,0 +1,47 @@
package main
import (
"github.com/gidsi/ics-golang"
"log"
)
func getCalendars() {
spaceDataArray := readSpacedata()
for _, spaceData := range spaceDataArray {
parser := ics.New()
parserChan := parser.GetInputChan()
parserChan <- spaceData.Feeds.Calendar.Url
outputChan := parser.GetOutputChan()
calendar := Calendar{}
calendar.Space = spaceData.Space
events := []Event{}
go func() {
for event := range outputChan {
events = append(events, mapEventObject(event))
}
}()
parser.Wait()
calendar.Events = events
writeCalendar(calendar)
log.Println("calendar write done for " + spaceData.Space)
}
}
func mapEventObject(event *ics.Event) Event {
eventData := Event{}
eventData.Start = event.GetStart()
eventData.ImportedId = event.GetImportedID()
eventData.Status = event.GetStatus()
eventData.Description = event.GetDescription()
eventData.Location = event.GetLocation()
eventData.Summary = event.GetSummary()
eventData.Rrule = event.GetRRule()
eventData.Url = event.GetUrl()
eventData.Class = event.GetClass()
eventData.Sequence = event.GetSequence()
eventData.WholeDayEvent = event.GetWholeDayEvent()
return eventData
}

3
backend/config.yaml Normal file
View file

@ -0,0 +1,3 @@
---
mongodb_server: database
mongodb_database: eva

7
backend/configFile.go Normal file
View file

@ -0,0 +1,7 @@
package main
type ConfigFile struct {
SharedSecret string `yaml:"shared_secret,omitempty"`
MongoDbServer string `yaml:"mongodb_server,omitempty"`
MongoDbDatabase string `yaml:"mongodb_database,omitempty"`
}

115
backend/database.go Normal file
View file

@ -0,0 +1,115 @@
package main
import (
"log"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
func writeSpaceData(data SpaceData) {
if(data.Space != "") {
session, err := mgo.Dial(config.MongoDbServer)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB(config.MongoDbDatabase).C("spacedata")
_, err = c.Upsert(bson.M{ "space": data.Space }, data)
if err != nil {
log.Fatal(err)
}
}
}
func writeSpaceurl(spaceUrl SpaceUrl) {
session, err := mgo.Dial(config.MongoDbServer)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB(config.MongoDbDatabase).C("spaceurl")
count, _ := c.Find(bson.M{ "url": spaceUrl.Url }).Count()
if(count == 0) {
c.Insert(spaceUrl);
}
}
func writeCalendar(calendar Calendar) {
session, err := mgo.Dial(config.MongoDbServer)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB(config.MongoDbDatabase).C("calendar")
c.Upsert(bson.M{ "space": calendar.Space }, calendar)
}
func updateSpaceurl(spaceUrl SpaceUrl) {
session, err := mgo.Dial(config.MongoDbServer)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB(config.MongoDbDatabase).C("spaceurl")
c.Update(bson.M{ "url": spaceUrl.Url }, spaceUrl);
}
func readSpacedata() []SpaceData {
session, err := mgo.Dial(config.MongoDbServer)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB(config.MongoDbDatabase).C("spacedata")
result := []SpaceData{}
c.Find(bson.M{}).Iter().All(&result)
return result
}
func readSpaceurl() []SpaceUrl {
session, err := mgo.Dial(config.MongoDbServer)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB(config.MongoDbDatabase).C("spaceurl")
result := []SpaceUrl{}
c.Find(bson.M{}).Iter().All(&result)
return result
}
func readCalendar() []Calendar {
session, err := mgo.Dial(config.MongoDbServer)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB(config.MongoDbDatabase).C("calendar")
result := []Calendar{}
c.Find(bson.M{}).Iter().All(&result)
return result
}

92
backend/eva-backend.go Normal file
View file

@ -0,0 +1,92 @@
package main
import (
"net/http"
"encoding/json"
"gopkg.in/yaml.v2"
"log"
"io/ioutil"
"os"
"time"
"github.com/gorilla/mux"
)
var config = ConfigFile{}
func main() {
data, _ := ioutil.ReadFile("config.yaml")
yaml.Unmarshal(data, &config)
config.SharedSecret = os.Getenv("SHARED_SECRET")
router := NewRouter()
http.Handle("/", router)
log.Fatal(http.ListenAndServe(":8080", router))
}
func getJson(url string, target interface{}) error {
r, err := http.Get(url)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
func SpaceDataIndex(w http.ResponseWriter, r *http.Request) {
ReturnJson(w, readSpacedata())
}
func SpaceUrlIndex(w http.ResponseWriter, r *http.Request) {
ReturnJson(w, readSpaceurl())
}
func CalendarIndex(w http.ResponseWriter, r *http.Request) {
ReturnJson(w, readCalendar())
}
func SpaceUrlAdd(w http.ResponseWriter, r *http.Request) {
spaceUrl := SpaceUrl{}
createEntry(&spaceUrl, w, r)
spaceUrl.Validated = false
writeSpaceurl(spaceUrl)
}
func SpaceUrlUpdate(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
SharedSecret := vars["SharedSecret"]
if(SharedSecret == config.SharedSecret) {
spaceUrl := SpaceUrl{}
createEntry(&spaceUrl, w, r)
updateSpaceurl(spaceUrl)
}
}
func loadSpaceData() {
spaceUrls := readSpaceurl()
timestamp := time.Now().Unix()
for _, spaceUrl := range spaceUrls {
if(spaceUrl.Validated && int64(spaceUrl.LastUpdated + 60) < timestamp) {
spaceData := SpaceData{}
err := getJson(spaceUrl.Url, &spaceData)
if(err != nil) {
log.Println(spaceUrl.Url)
log.Println(err)
} else {
writeSpaceData(spaceData)
spaceUrl.LastUpdated = timestamp
updateSpaceurl(spaceUrl)
}
}
}
}
func refreshData(w http.ResponseWriter, r *http.Request) {
loadSpaceData()
getCalendars()
w.WriteHeader(204)
}

23
backend/event.go Normal file
View file

@ -0,0 +1,23 @@
package main
import "time"
type Calendar struct {
Space string
Events []Event
}
type Event struct {
Start time.Time `json:"start"`
ImportedId string `json:"importId"`
Status string `json:"status"`
Description string `json:"description"`
Location string `json:"location"`
Summary string `json:"summary"`
Rrule string `json:"rrule"`
Class string `json:"class"`
Url string `json:"url"`
Sequence int `json:"sequence"`
WholeDayEvent bool `json:"whileDayEvent"`
}

29
backend/logger.go Normal file
View file

@ -0,0 +1,29 @@
package main
import (
"log"
"net/http"
"time"
)
func Logger(inner http.Handler, name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
inner.ServeHTTP(w, r)
log.Printf(
"%s\t%s\t%s\t%s",
r.Method,
r.RequestURI,
name,
time.Since(start),
)
})
}
func logError(err error) {
if err != nil {
log.Fatal(err)
}
}

48
backend/response.go Normal file
View file

@ -0,0 +1,48 @@
package main
import (
"net/http"
"encoding/json"
"fmt"
)
type DataObject interface {
Save() DataObject
}
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello? Yes, this is dog!")
}
func ReturnJson(w http.ResponseWriter, v interface{}) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "content-type")
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(v); err != nil {
panic(err)
}
}
func ReturnDataNotFound(w http.ResponseWriter) {
w.WriteHeader(http.StatusNotFound)
}
func createEntry(i interface{}, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "content-type")
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
if err := json.NewDecoder(r.Body).Decode(i); err != nil {
w.WriteHeader(422) // unprocessable entity
if err := json.NewEncoder(w).Encode(err); err != nil {
panic(err)
}
} else {
w.WriteHeader(http.StatusCreated)
if err := json.NewEncoder(w).Encode(i); err != nil {
panic(err)
}
}
}

51
backend/router.go Normal file
View file

@ -0,0 +1,51 @@
package main
import (
"net/http"
"github.com/gorilla/mux"
"log"
)
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range IndexRoutes {
var handler http.Handler
handler = Logger(route.Handler, route.Name)
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(handler)
router.
Methods("OPTIONS").
Name("Options Handler").
Handler(http.HandlerFunc(optionsHandler))
}
router.
Methods("OPTIONS").
Name("Options Handler").
Handler(http.HandlerFunc(optionsHandler))
router.NotFoundHandler = http.HandlerFunc(notFound)
return router
}
func notFound(w http.ResponseWriter, r *http.Request) {
log.Print("---------------------------------")
log.Print(w)
log.Print("---------------------------------")
log.Print(r)
log.Print("---------------------------------")
w.WriteHeader(http.StatusNotFound)
}
func optionsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE")
w.WriteHeader(200)
}

58
backend/routes.go Normal file
View file

@ -0,0 +1,58 @@
package main
import "net/http"
type Route struct {
Name string
Method string
Pattern string
Handler http.HandlerFunc
}
type Routes []Route
var IndexRoutes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
Route{
"SpaceDataIndex",
"GET",
"/spaces",
SpaceDataIndex,
},
Route{
"SpaceUrlIndex",
"GET",
"/urls",
SpaceUrlIndex,
},
Route{
"CalendarIndex",
"GET",
"/calendar",
CalendarIndex,
},
Route{
"SpaceUrlAdd",
"POST",
"/urls",
SpaceUrlAdd,
},
Route{
"SpaceUrlUpdate",
"PUT",
"/urls/{SharedSecret}",
SpaceUrlUpdate,
},
Route{
"RefreshData",
"GET",
"/refresh",
refreshData,
},
}

44
backend/spacedata.go Normal file
View file

@ -0,0 +1,44 @@
package main
type Feed struct {
Type string `json:"type"`
Url string `json:"url"`
}
type Location struct {
Address string `json:"address"`
Lon float32 `json:"lon"`
Lat float32 `json:"lat"`
}
type Contact struct {
Twitter string `json:"twitter"`
Phone string `json:"phone"`
Irc string `json:"irc"`
Email string `json:"email"`
Ml string `json:"ml"`
IssueMail string `json:"issue_mail"`
}
type State struct {
Open bool `json:"open"`
}
type Feeds struct {
Blog Feed `json:"blog"`
Wiki Feed `json:"wiki"`
Calendar Feed `json:"calendar"`
}
type SpaceData struct {
Api string `json:"api"`
Space string `json:"space"`
Logo string `json:"logo"`
Url string `json:"url"`
Location Location `json:"location"`
Contact Contact `json:"contact"`
IssueReportChannels []string `json:"issue_report_channels"`
State State `json:"state"`
Feeds Feeds `json:"feeds"`
Ext_ccc string `json:"ext_ccc"`
}

7
backend/spaceurl.go Normal file
View file

@ -0,0 +1,7 @@
package main
type SpaceUrl struct {
Url string `json:"url"`
Validated bool `json:"validated"`
LastUpdated int64 `json:"lastUpdated"`
}