Permalink
Browse files

Refactor everything into services and move to Postgres (#152)

* temp

* Move main package to subpackage

* Update Dockerfile with new main package path

* Begin refactoring

* Update pq

* Begin testing vehicle service

* Start reworking vehicles test

* Test content-type

* Test no vehicles response

* Add test for returned vehicles

* Add test for creating vehicle

* Add test for vehicle modification

* Actually test modification

* Switch vehicles routes away from chi URL parameters; test vehicle delete

* Verbose govendor output and fast finish

* Fix pq vendoring

* Remove useless handler

* Continue implementing vehicles in postgres

* Update comment

* Flesh out postgres vehicle service implementation

* Begin refactoring route and time

* yikes

* Add itrak time/date parsing test

* Fix tests

* Refactor AdminMessage into MessageService

* Create UserService

* Fix tests

* Add StopService

* Remove database package

* Update gitignore

* Implement postgres UserService queries

* Get latest locations and create locations

* Flesh out postgres location service

* Remove model and mongo packages

* Fix some linter issues

* Fix route guessing returning empty route instead of nil

* Read route points from database

* Flesh out route service

* Stop creating unused table

* Fix path regex to account for floating point

* Route creation and display

* Fix route guessing

* Fix updater iTRAK time parsing

* Flesh out message service

* Stops (not deletion)

* Preliminary stop ordering

* Order stops properly

* Delete stop ordering on route deletion

* Insert stop order with route

* Modify route can change stop ordering

* Stop using sort.Slice

* Stop deletion

* Fix some linter issues

* Rip out route scheduling stuff

* Read database connection info from environment/config file

* Update documentation

* Fix authenticate option

* Change IDs from int to int64

* Attempt to fix tests on Go 1.7

* Roll back to slightly older github.com/lib/pq

Newer versions require Go 1.8 or newer. I'd like to stay on 1.7
until it is no longer possible. There are a large number of people
who get 1.7 by installing Go from Debian or Ubuntu repos.

* 404 if deleting something that doesn't exist

* Fix typo

* Fix transaction rollback error checking linter warning

* Don't run linter on some functions

Updater wasn't actually modified in this PR (a refactor needs to
happen, but in another PR). The other is a test.

* Use renamed fields

* Try to fix gotype

* Fix types in frontend

* Fix route deletion in admin interface

* Try to have Travis run Postgres integration tests

* remove minor num

* Use older postgres because travis

* Fix table creation order

* Preliminary Postgres Location tests

* Tear down differently

* Suppress cyclo linting on tests

* Modify make/remove admin scripts

* Remove empty file

* Fix reference to Mongo in readme

* Update readme with more info about setting up

* Fix admin message modification and display

* Add MapBox API key info

* Fix spelling
  • Loading branch information...
kochman authored and garoller committed Sep 11, 2018
1 parent cdd56dc commit 4e37573fae52b579738ea04bffdfc7471d7b5f58
Showing with 2,518 additions and 1,575 deletions.
  1. +4 −3 .dockerignore
  2. +2 −3 .gitignore
  3. +11 −4 .travis.yml
  4. +2 −1 Dockerfile
  5. +21 −43 README.md
  6. +13 −22 api/api.go
  7. +6 −4 api/api_test.go
  8. +23 −15 api/casauth.go
  9. +11 −12 api/casauth_test.go
  10. +13 −10 api/notifications.go
  11. +55 −0 api/notifications_test.go
  12. +39 −106 api/routes.go
  13. +34 −39 api/vehicles.go
  14. +318 −0 api/vehicles_test.go
  15. +22 −9 cmd/{shuttletracker.go → shuttletracker/main.go}
  16. +4 −5 conf.json.sample
  17. +3 −3 config/config.go
  18. +0 −87 database/database.go
  19. +0 −117 database/database_test.go
  20. +0 −158 database/mock.go
  21. +0 −253 database/mongodb.go
  22. +9 −3 example_database/make-admin.sh
  23. +10 −4 example_database/remove-admin.sh
  24. +37 −0 location.go
  25. +0 −11 main.go
  26. +25 −0 message.go
  27. +38 −0 mock/location.go
  28. +24 −0 mock/message.go
  29. +9 −0 mock/model.go
  30. +42 −0 mock/route.go
  31. +29 −0 mock/stop.go
  32. +16 −0 mock/user.go
  33. +54 −0 mock/vehicle.go
  34. +9 −0 model.go
  35. +0 −143 model/model.go
  36. +0 −6 model/user.go
  37. +111 −0 postgres/location.go
  38. +206 −0 postgres/location_test.go
  39. +49 −0 postgres/message.go
  40. +76 −0 postgres/postgres.go
  41. +244 −0 postgres/route.go
  42. +75 −0 postgres/stop.go
  43. +32 −0 postgres/user.go
  44. +149 −0 postgres/vehicle.go
  45. +38 −0 route.go
  46. +295 −296 static/js/frontend.js
  47. +16 −16 static/js/messages.js
  48. +13 −7 static/js/routes.js
  49. +12 −18 static/js/stops.js
  50. +20 −12 static/js/vehicles.js
  51. +29 −0 stop.go
  52. +19 −7 {model → time}/time.go
  53. +34 −5 {model → time}/time_test.go
  54. +128 −104 updater/updater.go
  55. +35 −0 updater/updater_test.go
  56. +11 −0 user.go
  57. +30 −0 vehicle.go
  58. +13 −49 vendor/vendor.json
View
@@ -3,13 +3,14 @@
!auth
!cmd
!config
!database
!log
!model
!mock
!postgres
!static
!time
!updater
!vendor/vendor.json
!admin.html
!main.go
!*.go
!index.html
!CHECKS
View
@@ -1,5 +1,4 @@
bower_components
conf.json
*.swp
/conf.json
/vendor/*/
/coverage.txt
/shuttletracker
View
@@ -5,22 +5,29 @@ go:
- 1.8.x
- 1.9.x
- 1.10.x
- tip
- master
matrix:
allow_failures:
- go: tip
- go: master
fast_finish: true
services:
- docker
addons:
postgresql: "9.6"
before_install:
- go get -u github.com/kardianos/govendor && govendor sync
- go get -u github.com/kardianos/govendor && govendor sync -v
- go get -u github.com/alecthomas/gometalinter && gometalinter --install
- go get -u github.com/bradleyfalzon/revgrep/...
install:
- go install
- go install github.com/wtg/shuttletracker/cmd/shuttletracker
before_script:
- psql -c 'create database shuttletracker_test;' -U postgres
script:
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then gometalinter --vendor ./... 2>&1 | revgrep origin/master; fi
View
@@ -6,10 +6,11 @@ WORKDIR /go/src/github.com/wtg/shuttletracker
COPY vendor/vendor.json ./vendor/
RUN govendor sync
COPY . /go/src/github.com/wtg/shuttletracker
RUN go install github.com/wtg/shuttletracker
RUN go install github.com/wtg/shuttletracker/cmd/shuttletracker
# Dokku checks http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/
RUN mkdir /app
COPY CHECKS /app
EXPOSE 8080
CMD ["/go/bin/shuttletracker"]
View
@@ -1,57 +1,35 @@
# Shuttle Tracker [![Build Status](https://travis-ci.org/wtg/shuttletracker.svg?branch=master)](https://travis-ci.org/wtg/shuttletracker) [![codecov](https://codecov.io/gh/wtg/shuttletracker/branch/master/graph/badge.svg)](https://codecov.io/gh/wtg/shuttletracker) [![GoDoc](https://godoc.org/github.com/wtg/shuttletracker?status.svg)](https://godoc.org/github.com/wtg/shuttletracker) [![Go Report Card](https://goreportcard.com/badge/github.com/wtg/shuttletracker)](https://goreportcard.com/report/github.com/wtg/shuttletracker)
Tracking and mapping RPI's shuttles with [Go](https://golang.org/), [Vue.js](https://vuejs.org/), and [MongoDB](https://www.mongodb.org/).
Tracking and mapping RPI's shuttles with [Go](https://golang.org/), [Vue.js](https://vuejs.org/), and [Postgres](https://www.postgresql.org).
Check it out in action at [shuttles.rpi.edu](https://shuttles.rpi.edu).
## Setting Up
## Setting up
1. Install Go (https://golang.org/doc/install)
2. Ensure your `$GOPATH` is set correctly, and is apart of your `$PATH`
1. [Install Go](https://golang.org/doc/install). Shuttle Tracker targets Go 1.7 and newer, but we recommend using the latest Go stable release.
2. Ensure your `$GOPATH` is set correctly, and `$GOPATH/bin` is in your `$PATH`
3. Run `go get github.com/wtg/shuttletracker`
4. Install `govendor` by running `go get -u github.com/kardianos/govendor`
4. Install `govendor` by running `go get -u github.com/kardianos/govendor`
5. Switch to the Shuttle Tracker directory (`$GOPATH/src/github.com/wtg/shuttletracker`)
6. Run `govendor sync`
7. Ensure you have MongoDB installed.
8. Rename `conf.json.sample` to `conf.json`
9. Edit conf.json with the following:
* `DataFeed`: API with tracking information from iTrak... For RPI, this is a unique API URL that we can get data from. It's currently private, and we will only share it with authorized members for now.
* `UpdateInterval`: Number of seconds between each request to the data feed
* `MongoUrl`: URL where MongoDB is located
* `MongoPort`: Port where MongoDB is bound (default is 27017)
10. Start MongoDB, and ensure it is running, and listening on port 27017 (or whichever port you defined in `MongoPort` within `conf.json`)
7. Ensure you have [Postgres downloaded](https://www.postgresql.org/download/), installed, and running. On macOS, prefer installing it with Homebrew.
8. Run `createdb shuttletracker` to create a Postgres database.
9. Rename `conf.json.sample` to `conf.json`
10. Edit `conf.json` with the following, if necessary:
* `Updater.DataFeed`: API with tracking information from iTrak. For RPI, this is a unique API URL that we can get data from. It's private, and a Shuttle Tracker developer can provide it to you.
* `API.MapboxAPIKey`: Necessary for creating routes through the admin interface. [Create your own token](https://www.mapbox.com/help/how-access-tokens-work/) or ask a Shuttle Tracker developer to provide you with one.
* `Postgres.URL`: URL where Postgres is located. The provided default typically won't need to be modified.
11. Add data to your database. Example DBs are provided in `example_database`, as well as a simple import/export script to setup the database for you.
- If using an example database, you might need to check the name of the imported database, and change `MongoUrl` accordingly.
12. Start the app by running `go run main.go` in the project root directory.
13. You can optionally add yourself as an administrator by using the `make-admin` script in the example_database folder, passing it your RCS ID as the first argument.
- If using an example database, you might need to check the name of the imported database and change the Postgres URL accordingly.
12. Start the app by running `go run cmd/shuttletracker/main.go` in the project root directory.
13. You can optionally add yourself as an administrator by using the `make-admin.sh` script in the example_database folder, passing it your RCS ID as the first argument.
14. Visit http://localhost:8080/ to view the tracking application and http://localhost:8080/admin to view the administration panel
## Configuration
Shuttle Tracker reads from a `conf.json` file. It can look like this:
```
{
"Updater": {
"DataFeed": "",
"UpdateInterval": "3s"
},
"API": {
"GoogleMapAPIKey": "",
"GoogleMapMinDistance": 1,
"CasURL": "https://cas-auth.rpi.edu/cas/",
"Authenticate": true,
"ListenURL": "127.0.0.1:8080"
},
"Database": {
"MongoURL": "127.0.0.1:27017"
},
"Log": {
"Level": "debug"
}
}
```
### Environment Variables
Most keys can be overridden with environment variables. The variables names usually take the format `SECTION_KEY`. For example, overriding database's Mongo URL could be done with a variable named `DATABASE_MONGOURL`.
Shuttle Tracker needs configuration to run properly. The preferred method during development is to create a `conf.json` file. See `conf.json.sample` for an example of what it should contain.
### Environment variables
Most keys can be overridden with environment variables. The variables names usually take the format `SECTION_KEY`. For example, overriding database's Mongo URL could be done with a variable named `POSTGRES_URL`.
View
@@ -10,11 +10,11 @@ import (
"github.com/go-chi/chi/middleware"
"github.com/spf13/viper"
"github.com/wtg/shuttletracker/database"
"github.com/wtg/shuttletracker"
"github.com/wtg/shuttletracker/log"
)
// Configuration holds the settings for connecting to outside resources.
// Config holds API settings.
type Config struct {
GoogleMapAPIKey string
GoogleMapMinDistance int
@@ -24,16 +24,17 @@ type Config struct {
MapboxAPIKey string
}
// App holds references to Mongo resources.
// API is responsible for configuring handlers for HTTP endpoints.
type API struct {
cfg Config
db database.Database
handler http.Handler
ms shuttletracker.ModelService
msg shuttletracker.MessageService
}
// InitApp initializes the application given a config and connects to backends.
// New initializes the application given a config and connects to backends.
// It also seeds any needed information to the database.
func New(cfg Config, db database.Database) (*API, error) {
func New(cfg Config, ms shuttletracker.ModelService, msg shuttletracker.MessageService, us shuttletracker.UserService) (*API, error) {
// Set up CAS authentication
url, err := url.Parse(cfg.CasURL)
if err != nil {
@@ -43,16 +44,16 @@ func New(cfg Config, db database.Database) (*API, error) {
// Create API instance to store database session and collections
api := API{
cfg: cfg,
db: db,
ms: ms,
msg: msg,
}
r := chi.NewRouter()
r.Use(middleware.DefaultCompress)
r.Use(etag)
cli := CreateCASClient(url, db)
cli := CreateCASClient(url, us, cfg.Authenticate)
// Vehicles
r.Route("/vehicles", func(r chi.Router) {
@@ -61,7 +62,7 @@ func New(cfg Config, db database.Database) (*API, error) {
r.Use(cli.casauth)
r.Post("/create", api.VehiclesCreateHandler)
r.Post("/edit", api.VehiclesEditHandler)
r.Delete("/{id:[0-9]+}", api.VehiclesDeleteHandler)
r.Delete("/", api.VehiclesDeleteHandler)
})
})
@@ -74,7 +75,6 @@ func New(cfg Config, db database.Database) (*API, error) {
r.Route("/adminMessage", func(r chi.Router) {
r.Get("/", api.AdminMessageHandler)
r.Group(func(r chi.Router) {
r.Use(cli.casauth)
r.Post("/", api.SetAdminMessage)
})
@@ -86,21 +86,18 @@ func New(cfg Config, db database.Database) (*API, error) {
r.Group(func(r chi.Router) {
r.Use(cli.casauth)
r.Post("/create", api.RoutesCreateHandler)
r.Post("/schedule", api.RoutesScheduler)
r.Post("/edit", api.RoutesEditHandler)
r.Delete("/{id:.+}", api.RoutesDeleteHandler)
r.Delete("/", api.RoutesDeleteHandler)
})
})
// Stops
r.Route("/stops", func(r chi.Router) {
r.Get("/", api.StopsHandler)
r.Group(func(r chi.Router) {
r.Use(cli.casauth)
r.Post("/create", api.StopsCreateHandler)
r.Delete("/{id:.+}", api.StopsDeleteHandler)
r.Delete("/", api.StopsDeleteHandler)
})
})
@@ -111,12 +108,10 @@ func New(cfg Config, db database.Database) (*API, error) {
r.Get("/", api.AdminHandler)
r.Get("/login", api.AdminHandler)
r.Get("/logout", cli.logout)
})
r.Group(func(r chi.Router) {
r.Use(cli.casauth)
r.Get("/getKey/", api.KeyHandler)
})
@@ -171,10 +166,6 @@ func (api *API) KeyHandler(w http.ResponseWriter, r *http.Request) {
}
}
func (api *API) AdminLogout(w http.ResponseWriter, r *http.Request) {
}
// WriteJSON writes the data as JSON.
func WriteJSON(w http.ResponseWriter, data interface{}) error {
w.Header().Set("Content-Type", "application/json")
View
@@ -7,7 +7,7 @@ import (
"os"
"testing"
"github.com/wtg/shuttletracker/database"
"github.com/wtg/shuttletracker/mock"
)
func TestStatic(t *testing.T) {
@@ -34,11 +34,13 @@ func TestStatic(t *testing.T) {
os.Chdir("..")
cfg := Config{}
db := &database.Mock{}
ms := &mock.ModelService{}
msg := &mock.MessageService{}
us := &mock.UserService{}
api, err := New(cfg, db)
api, err := New(cfg, ms, msg, us)
if err != nil {
t.Errorf("got error '%s', expected nil", err)
t.Errorf("unexpected error: %s", err)
return
}
View
@@ -1,25 +1,26 @@
package api
import (
"github.com/wtg/shuttletracker/auth"
"github.com/wtg/shuttletracker/database"
"github.com/wtg/shuttletracker/log"
"net/http"
"net/url"
"strings"
gc "gopkg.in/cas.v2"
"net/http"
"strings"
"github.com/wtg/shuttletracker"
"github.com/wtg/shuttletracker/auth"
"github.com/wtg/shuttletracker/log"
)
// CASClient stores the local cas client and an instance of the database
type CASClient struct {
cas auth.AuthenticationService
db database.Database
cas auth.AuthenticationService
us shuttletracker.UserService
authenticate bool
}
// CreateCASClient creates an authentication service CASClient using a cas url and database
func CreateCASClient(url *url.URL, db database.Database) (*CASClient){
func CreateCASClient(url *url.URL, us shuttletracker.UserService, authenticate bool) *CASClient {
client := gc.NewClient(&gc.Options{
URL: url,
Store: nil,
@@ -29,17 +30,18 @@ func CreateCASClient(url *url.URL, db database.Database) (*CASClient){
cas: &auth.CAS{
CAS: client,
},
db: db,
us: us,
authenticate: authenticate,
}
return cli
}
// InjectMocks allows mock interfaces to be used
func InjectMocks(cli auth.AuthenticationService, db database.Database) (*CASClient){
c:= &CASClient{
cas: cli,
db: db,
func InjectMocks(cli auth.AuthenticationService, us shuttletracker.UserService, auth bool) *CASClient {
c := &CASClient{
cas: cli,
us: us,
authenticate: auth,
}
return c
}
@@ -51,6 +53,12 @@ func (cli *CASClient) logout(w http.ResponseWriter, r *http.Request) {
func (cli *CASClient) casauth(next http.Handler) http.Handler {
return cli.cas.HandleFunc(func(w http.ResponseWriter, r *http.Request) {
if !cli.authenticate {
// don't authenticate
next.ServeHTTP(w, r)
return
}
if !cli.cas.Authenticated(r) {
_, err := w.Write([]byte("redirecting to cas;"))
if err != nil {
@@ -59,7 +67,7 @@ func (cli *CASClient) casauth(next http.Handler) http.Handler {
}
cli.cas.Login(w, r)
} else {
auth, err := cli.db.UserExists(strings.ToLower(cli.cas.Username(r)))
auth, err := cli.us.UserExists(strings.ToLower(cli.cas.Username(r)))
if err != nil {
log.WithError(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
Oops, something went wrong.

0 comments on commit 4e37573

Please sign in to comment.