merge eva repos into single repository
This commit is contained in:
commit
200dd620ae
52 changed files with 2281 additions and 0 deletions
2
backend/.gitignore
vendored
Normal file
2
backend/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
eva-backend
|
||||
.idea
|
||||
15
backend/Dockerfile
Normal file
15
backend/Dockerfile
Normal 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
15
backend/README.md
Normal 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
47
backend/calendar.go
Normal 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
3
backend/config.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
mongodb_server: database
|
||||
mongodb_database: eva
|
||||
7
backend/configFile.go
Normal file
7
backend/configFile.go
Normal 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
115
backend/database.go
Normal 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
92
backend/eva-backend.go
Normal 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
23
backend/event.go
Normal 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
29
backend/logger.go
Normal 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
48
backend/response.go
Normal 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
51
backend/router.go
Normal 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
58
backend/routes.go
Normal 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
44
backend/spacedata.go
Normal 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
7
backend/spaceurl.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
type SpaceUrl struct {
|
||||
Url string `json:"url"`
|
||||
Validated bool `json:"validated"`
|
||||
LastUpdated int64 `json:"lastUpdated"`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue