Currently we have some license issues. We are working on it.

Commit c8b5b7d9 authored by zauberstuhl's avatar zauberstuhl
Browse files

Merge branch 'vuejs' into 'master'

Vuejs

See merge request !1
parents 9f4a3d89 a76c71cc
config.yml
*.db
vendor/
unmappd
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
FROM golang:buster
RUN apt-get update && apt-get install -y npm
RUN npm install --global yarn
ADD . /go/src/build
WORKDIR /go/src/build
RUN yarn build
RUN go build -o unmappd
FROM debian:buster
......@@ -12,13 +16,13 @@ RUN apt-get clean && apt-get autoclean
RUN adduser --disabled-password app
ADD . /home/app
COPY --from=0 /go/src/build/unmappd /home/app/unmappd
COPY --from=0 /go/src/build/dist/ /home/app/dist/
COPY --from=0 /go/src/build/unmappd /home/app/
COPY --from=0 /go/src/build/config.yml.example /home/app/config.yml
RUN chmod +x /home/app/unmappd
WORKDIR /home/app
RUN cp config.yml.example config.yml
RUN rm -rf vendor *.db
EXPOSE 8080
......
......@@ -2,6 +2,13 @@
## Build
### Compile assets
yarn install
yarn build
### Compile binary
go build -o unmappd
## Docker image
......
......@@ -94,7 +94,7 @@ func auth_handler(w http.ResponseWriter, r *http.Request) {
return
}
userParam := "/users/%s"
userParam := "#/map/%s"
err = db.First(&User{}, "username = ?", username).Error
if err == nil {
http.Redirect(w, r,
......@@ -135,7 +135,11 @@ func fetch_auth(code string) (string, error) {
var uauth Uauthresp
return uauth.Response.Access_token, get(fmt.Sprintf(
"https://untappd.com/oauth/authorize/?client_id=%s&client_secret=%s&response_type=code&redirect_url=%s&code=%s",
CLIENTID, CLIENTSECRET, REDIRECTURL, code), &uauth)
viper.GetString("clientID"),
viper.GetString("clientSecret"),
viper.GetString("redirectUrl"),
code,
), &uauth)
}
func fetch_user_info(token string) (info Uinfo, err error) {
......
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
redirectUrl: http://localhost:8080
redirectUrl: http://localhost:8080/api/v0/auth
# untappd app secret
clientID: 1234
......
......@@ -25,8 +25,6 @@ import (
"github.com/spf13/viper"
)
var CLIENTID, CLIENTSECRET, REDIRECTURL string
func init() {
viper.SetConfigName("config")
viper.AddConfigPath(".")
......@@ -44,10 +42,6 @@ func init() {
log.Print("Run migrations..")
db.AutoMigrate(&Location{})
db.AutoMigrate(&User{})
CLIENTID = viper.GetString("clientID")
CLIENTSECRET = viper.GetString("clientSecret")
REDIRECTURL = viper.GetString("redirectUrl")
}
func main() {
......@@ -55,12 +49,15 @@ func main() {
Addr: "0.0.0.0:8080",
}
http.HandleFunc("/", index_handler)
http.HandleFunc("/users/", user_handler)
http.HandleFunc("/api/v0/config", config_handler)
http.HandleFunc("/api/v0/users/", user_handler)
http.HandleFunc("/api/v0/locations/", location_handler)
http.HandleFunc("/api/v0/auth", auth_handler)
// NOTE will be obsolete in future
http.HandleFunc("/auth", auth_handler)
// assets directory
fs := http.FileServer(http.Dir("public"))
http.Handle("/assets/", http.StripPrefix("/assets/", fs))
fs := http.FileServer(http.Dir("dist"))
http.Handle("/", http.StripPrefix("/", fs))
log.Print("Listening on 0.0.0.0:8080 ..")
server.ListenAndServe()
......
......@@ -20,12 +20,9 @@ package main
import (
"time"
"html/template"
"strings"
"fmt"
"github.com/spf13/viper"
"github.com/microcosm-cc/bluemonday"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
_ "github.com/jinzhu/gorm/dialects/mysql"
......@@ -33,22 +30,22 @@ import (
)
type User struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
Username string `gorm:"unique_index;size:191"`
Token string `gorm:"index;size:191"`
TotalBadges int
TotalFriends int
TotalCheckins int
TotalBeers int
TotalCreatedBeers int
TotalFollowings int
TotalPhotos int
Locations Locations
ID uint `gorm:"primary_key" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"-"`
Username string `gorm:"unique_index;size:191" json:"-"`
Token string `gorm:"index;size:191" json:"-"`
TotalBadges int `json:"totalBadges"`
TotalFriends int `json:"totalFriends"`
TotalCheckins int `json:"totalCheckins"`
TotalBeers int `json:"totalBeers"`
TotalCreatedBeers int `json:"totalCreatedBeers"`
TotalFollowings int `json:"totalFollowings"`
TotalPhotos int `json:"totalPhotos"`
Locations Locations `json:"-"`
}
type Users []User
......@@ -58,47 +55,22 @@ func (user *User) AfterFind(db *gorm.DB) error {
}
type Location struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
ID uint `gorm:"primary_key" json:"id"`
CreatedAt time.Time `json:"-"`
UserID uint `gorm:"index"`
UserID uint `gorm:"index" json:"-"`
Lat, Lng float64
Url, Name, Category, Icon string
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
Url string `json:"url"`
Name string `json:"name"`
Category string `json:"category"`
Icon string `json:"icon"`
}
type Locations []Location
func (locations Locations) LatLngJSON() template.JS {
var result string
var format = `[%f,%f,{
timestamp:%d,
venue:{
icon:"%s",
name:"%s",
url:"%s",
category:"%s"
}
}],`
html := bluemonday.UGCPolicy()
for _, location := range locations {
result += fmt.Sprintf(format,
location.Lat,
location.Lng,
location.CreatedAt.Unix(),
location.Icon,
html.Sanitize(location.Name),
location.Url,
html.Sanitize(location.Category),
)
}
// trim last comma
result = strings.TrimRight(result, ",")
result = fmt.Sprintf("[%s]", result)
return template.JS(result)
}
func openDatabase() (*gorm.DB, error) {
driver := viper.GetString("db.driver")
url := viper.GetString("db.url")
......@@ -117,3 +89,18 @@ func openDatabase() (*gorm.DB, error) {
db.LogMode(true)
return db, err
}
func userByUsername(username string) (*User, error) {
db, err := openDatabase()
if err != nil {
return nil, err
}
defer db.Close()
var user User
err = db.First(&user, "username = ?", username).Error
if err == nil && viper.GetBool("worker") && len(user.Locations) == 0 {
go checkin_worker(&user, true)
}
return &user, err
}
{
"name": "unmappd",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.21.1",
"bootstrap": "^4.6.0",
"bootstrap-vue": "^2.21.2",
"core-js": "^3.6.5",
"leaflet": "^1.7.1",
"leaflet-gesture-handling": "^1.2.1",
"vue": "^2.6.12",
"vue-router": "^3.5.1",
"vue2-leaflet": "^2.6.0",
"vue2-leaflet-markercluster": "^3.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"vue-template-compiler": "^2.6.11"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
html, body {
height: 100%;
}
#mapid {
height: calc(100% - 96px);
height: -o-calc(100% - 96px);
height: -webkit-calc(100% - 96px);
height: -moz-calc(100% - 96px);
}
This diff is collapsed.
.leaflet-control-playback{position:relative;background-color:#7cbdf5;padding:10px;}
.leaflet-control-playback .optionsContainer{position:relative;}
.leaflet-control-playback .optionsContainer > div {
display: inline-block;
}
.leaflet-control-playback .buttonContainer {}
.leaflet-control-playback .buttonContainer a {
display: inline-block;
width: 32px;
height: 32px;
text-decoration: none;
}
.leaflet-control-playback .buttonContainer .btn-stop {
background: url(../images/icon-play.png) no-repeat center;
}
.leaflet-control-playback .buttonContainer .btn-start {
background: url(../images/icon-stop.png) no-repeat center;
}
.leaflet-control-playback .buttonContainer .btn-restart {
background: url(../images/icon-restart.png) no-repeat center;
}
.leaflet-control-playback .buttonContainer .btn-slow {
background: url(../images/icon-slow.png) no-repeat center;
}
.leaflet-control-playback .buttonContainer .btn-quick {
background: url(../images/icon-quick.png) no-repeat center;
}
.leaflet-control-playback .buttonContainer .btn-close {
background: url(../images/icon-close.png) no-repeat center;
}
.leaflet-control-playback .infoContainer {}
.leaflet-control-playback .sliderContainer {}
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg,
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
-ms-touch-action: pinch-zoom;
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
-ms-touch-action: none;
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
z-index: 800;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-tile {
will-change: opacity;
}
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;