Все работает

actency-mysql57-replication
Andrey Ivanov 2021-01-09 22:48:49 +03:00 committed by ya@tiburon.su
parent 5c6fd7ebd8
commit 3995e66713
10 changed files with 220 additions and 72 deletions

View File

@ -1,6 +1,7 @@
package main
import (
"fmt"
"github.com/codegangsta/martini"
"github.com/codegangsta/martini-contrib/binding"
"github.com/codegangsta/martini-contrib/render"
@ -25,7 +26,7 @@ func main() {
m := martini.Classic()
app, err := application.New("application.conf", "APP")
if err != nil {
log.Fatalf("cn't configure app")
log.Fatal(fmt.Errorf("can't build app: %w", err).Error())
}
m.Map(log.New(os.Stdout, "[app]", log.Lshortfile))
@ -33,7 +34,7 @@ func main() {
m.Use(sessions.Sessions("app", sessions.NewCookieStore([]byte("BfyfgIyngIOUgmOIUgt87thrg5RHn78b"))))
m.Use(auth.SessionUser(auth.GenerateAnonymousUser))
m.Use(render.Renderer(render.Options{
Directory: "templates",
Directory: "templates",
Extensions: []string{".tmpl"},
}))
@ -57,6 +58,9 @@ func main() {
m.Get("/signup", handlers.GetSignup)
m.Post("/signup", binding.Bind(auth.UserModel{}), handlers.PostSignup)
m.Get("/subscribe", handlers.GetSubscribe)
m.Get("/unsubscribe", handlers.GetUnSubscribe)
//Анкета текущего пользователя
m.Get("/", auth.LoginRequired, handlers.GetHome)

5
go.mod
View File

@ -3,16 +3,11 @@ module github.com/tiburon-777/OTUS_HighLoad
go 1.15
require (
github.com/BurntSushi/toml v0.3.1
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
github.com/codegangsta/martini v0.0.0-20170121215854-22fa46961aab
github.com/codegangsta/martini-contrib v0.0.0-20140208234550-8ce6181c2609
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab // indirect
github.com/go-sql-driver/mysql v1.5.0
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/martini-contrib/cors v0.0.0-20141016003011-553b9208d353
github.com/stretchr/testify v1.6.1
github.com/tiburon-777/modules v0.0.0-20201210103219-a0362a8da783
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)

4
go.sum
View File

@ -12,8 +12,6 @@ github.com/codegangsta/martini-contrib v0.0.0-20140208234550-8ce6181c2609/go.mod
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
@ -25,8 +23,6 @@ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/martini-contrib/cors v0.0.0-20141016003011-553b9208d353 h1:kXDXsKbuZYwJXBVeLT49PwPvAfQg74/8mOZUqrfV3cg=
github.com/martini-contrib/cors v0.0.0-20141016003011-553b9208d353/go.mod h1:ZQqqR+M04limsCsRirtK4IAN2ioLKKNxhvl7f0U40yw=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

View File

@ -5,41 +5,70 @@ import (
"fmt"
"github.com/tiburon-777/OTUS_HighLoad/internal/models"
"github.com/tiburon-777/modules/core/config"
"log"
)
type App struct {
Config *models.Configuration
DB *sql.DB
DB *sql.DB
}
func New(configFile, envPrefix string) (App, error) {
conf, err := configure(configFile, envPrefix)
if err != nil{
return App{}, fmt.Errorf("can't apply config: %w\n",err)
if err != nil {
return App{}, fmt.Errorf("can't apply config: %w\n", err)
}
db, err := sql.Open("mysql", conf.DSN.User+":"+conf.DSN.Pass+"@tcp("+conf.DSN.Host+":"+conf.DSN.Port+")/"+conf.DSN.Base)
if err != nil {
panic(err.Error())
return App{}, err
}
if err = dbInit(db); err != nil {
return App{}, err
}
return App{Config: conf, DB: db}, nil
}
func configure(fileName string, envPrefix string) (*models.Configuration,error) {
func configure(fileName string, envPrefix string) (*models.Configuration, error) {
var conf models.Configuration
s := config.New(&conf)
if fileName != "" {
fmt.Printf("try to apply config from file %s...\n", fileName)
log.Printf("try to apply config from file %s...\n", fileName)
if err := s.SetFromFile(fileName); err != nil {
return &models.Configuration{}, fmt.Errorf("can't apply config from file: %w", err)
}
}
if envPrefix != "" {
fmt.Printf("try to apply config from environment...\n")
log.Println("try to apply config from environment...")
if err := s.SetFromEnv(envPrefix); err != nil {
return &models.Configuration{}, fmt.Errorf("can't apply envvars to config:%w", err)
}
}
return &conf, nil
}
}
func dbInit(db *sql.DB) error {
log.Println("Check DB tables consistency...")
if _, err := db.Exec(`CREATE TABLE IF NOT EXISTS users (
Id int(11) NOT NULL AUTO_INCREMENT,
Username varchar(255) DEFAULT NULL,
Password varchar(255) DEFAULT NULL,
Name varchar(255) DEFAULT NULL,
Surname varchar(255) DEFAULT NULL,
BirthDate datetime DEFAULT NULL,
Gender varchar(255) DEFAULT NULL,
City varchar(255) DEFAULT NULL,
Interests varchar(255) DEFAULT NULL,
PRIMARY KEY (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8`); err != nil {
return err
}
if _, err := db.Exec(`CREATE TABLE IF NOT EXISTS relations (
userId int(11) DEFAULT NULL,
friendId int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8`); err != nil {
return err
}
log.Println("All tables exists")
return nil
}

View File

@ -2,12 +2,12 @@ package auth
import (
"fmt"
"github.com/codegangsta/martini"
"github.com/codegangsta/martini-contrib/render"
"github.com/codegangsta/martini-contrib/sessions"
"github.com/codegangsta/martini"
"github.com/codegangsta/martini-contrib/render"
"github.com/codegangsta/martini-contrib/sessions"
"github.com/tiburon-777/OTUS_HighLoad/internal/application"
"log"
"net/http"
"net/http"
)
// These are the default configuration values for this package. They
@ -100,4 +100,3 @@ func UpdateUser(s sessions.Session, user User) error {
s.Set(SessionKey, user.UniqueId())
return nil
}

View File

@ -7,18 +7,19 @@ import (
)
type UserModel struct {
Id int64 `db:"id" form:"id"`
Username string `db:"username" form:"username"`
Password string `db:"password" form:"password"`
Name string `db:"name" form:"name"`
Surname string `db:"surname" form:"surname"`
BirthDate time.Time `db:"birthdate"`
YearsOld int `db:"-" form:"-"`
FormBirthDate string `form:"birthdate"`
Gender string `db:"gender" form:"gender"`
City string `db:"city" form:"city"`
Interests string `db:"interests" form:"interests"`
authenticated bool `db:"-" form:"-"`
Id int64 `db:"id" form:"id"`
Username string `db:"username" form:"username"`
Password string `db:"password" form:"password"`
Name string `db:"name" form:"name"`
Surname string `db:"surname" form:"surname"`
BirthDate time.Time `db:"birthdate"`
YearsOld int `db:"-" form:"-"`
FormBirthDate string `form:"birthdate"`
Gender string `db:"gender" form:"gender"`
City string `db:"city" form:"city"`
Interests string `db:"interests" form:"interests"`
IsFriend bool `db:"-" form:"-"`
authenticated bool `db:"-" form:"-"`
}
func GenerateAnonymousUser() User {
@ -59,6 +60,6 @@ func (u *UserModel) GetById(app application.App, id interface{}) error {
if err != nil {
return err
}
u.Id=id.(int64)
u.Id = id.(int64)
return nil
}
}

View File

@ -9,13 +9,50 @@ import (
"github.com/tiburon-777/OTUS_HighLoad/internal/auth"
"log"
"net/http"
"strconv"
"time"
)
func GetHome(r render.Render, user auth.User) {
func GetHome(app application.App, r render.Render, user auth.User) {
h := user.(*auth.UserModel).BirthDate
user.(*auth.UserModel).YearsOld = int(time.Since(h).Hours()/8760)
r.HTML(200, "index", user)
user.(*auth.UserModel).YearsOld = int(time.Since(h).Hours() / 8760)
doc := make(map[string]interface{})
doc["user"] = user.(*auth.UserModel)
var users []auth.UserModel
var tmp auth.UserModel
var tmpTime string
query := fmt.Sprintf(`SELECT
users.id as id,
users.name as name,
users.surname as surname,
users.birthdate as birthdate,
users.gender as gender,
users.city as city
FROM
users JOIN relations
WHERE
relations.friendId=users.Id
AND relations.userId="%s"
GROUP BY users.Id`,
strconv.Itoa(int(user.(*auth.UserModel).Id)),
)
var results, err = app.DB.Query(query)
if err != nil || results == nil {
err500("can't get user list from DB: ", err, r)
}
defer results.Close()
for results.Next() {
err = results.Scan(&tmp.Id, &tmp.Name, &tmp.Surname, &tmpTime, &tmp.Gender, &tmp.City)
if err != nil {
err500("can't scan result from DB: ", err, r)
}
tmp.BirthDate = str2Time(tmpTime, r)
tmp.YearsOld = int(time.Since(tmp.BirthDate).Hours() / 8760)
users = append(users, tmp)
}
doc["table"] = users
r.HTML(200, "index", doc)
}
func GetSignup(r render.Render) {
@ -35,7 +72,7 @@ func PostSignup(app application.App, postedUser auth.UserModel, r render.Render)
query := fmt.Sprintf(`INSERT INTO users (username, password, name, surname, birthdate, gender, city, interests)
values ("%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s")`,
postedUser.Username,
base64.StdEncoding.EncodeToString([]byte(postedUser.Username + ":" + postedUser.Password)),
base64.StdEncoding.EncodeToString([]byte(postedUser.Username+":"+postedUser.Password)),
postedUser.Name,
postedUser.Surname,
t.Format("2006-01-02 15:04:05"),
@ -52,35 +89,35 @@ func PostSignup(app application.App, postedUser auth.UserModel, r render.Render)
func GetUserList(app application.App, user auth.User, r render.Render) {
doc := make(map[string]interface{})
doc["user"]=user.(*auth.UserModel)
doc["user"] = user.(*auth.UserModel)
var users []auth.UserModel
var tmp auth.UserModel
var tmpTime string
var results, err = app.DB.Query(`SELECT name, surname, birthdate, gender, city FROM users`)
if err != nil || results==nil {
var results, err = app.DB.Query(`SELECT id, name, surname, birthdate, gender, city FROM users`)
if err != nil || results == nil {
err500("can't get user list from DB: ", err, r)
}
defer results.Close()
defer results.Close()
for results.Next() {
err = results.Scan(&tmp.Name, &tmp.Surname, &tmpTime, &tmp.Gender, &tmp.City)
err = results.Scan(&tmp.Id, &tmp.Name, &tmp.Surname, &tmpTime, &tmp.Gender, &tmp.City)
if err != nil {
err500("can't scan result from DB: ", err, r)
}
tmp.BirthDate = str2Time(tmpTime, r)
tmp.YearsOld = int(time.Since(tmp.BirthDate).Hours()/8760)
users = append(users,tmp)
tmp.YearsOld = int(time.Since(tmp.BirthDate).Hours() / 8760)
users = append(users, tmp)
}
doc["table"]=users
doc["table"] = users
r.HTML(200, "list", doc)
}
func PostLogin(app application.App, session sessions.Session, postedUser auth.UserModel, r render.Render, req *http.Request) {
hash := base64.StdEncoding.EncodeToString([]byte(postedUser.Username + ":" + postedUser.Password))
hash := base64.StdEncoding.EncodeToString([]byte(postedUser.Username + ":" + postedUser.Password))
user := auth.UserModel{}
query := fmt.Sprintf("SELECT id FROM users WHERE username=\"%s\" and password =\"%s\"", postedUser.Username, hash)
err := app.DB.QueryRow(query).Scan(&user.Id)
if err != nil || user.Id==0 {
if err != nil || user.Id == 0 {
r.Redirect(auth.RedirectUrl)
return
} else {
@ -95,6 +132,47 @@ func PostLogin(app application.App, session sessions.Session, postedUser auth.Us
}
}
func GetSubscribe(app application.App, r render.Render, user auth.User, req *http.Request) {
sid, ok := req.URL.Query()["id"]
if !ok {
err500("can't parce URL query", nil, r)
}
did, err := strconv.Atoi(sid[0])
if err != nil {
err500("can't convert URL query value: ", err, r)
}
query := fmt.Sprintf(`REPLACE INTO relations (userId, friendId) values ("%d", "%d")`,
user.(*auth.UserModel).Id,
did,
)
_, err = app.DB.Exec(query)
if err != nil {
err500("can't create relation in DB: ", err, r)
}
r.Redirect("/list")
}
func GetUnSubscribe(app application.App, r render.Render, user auth.User, req *http.Request) {
sid, ok := req.URL.Query()["id"]
if !ok {
err500("can't parce URL query", nil, r)
}
did, err := strconv.Atoi(sid[0])
if err != nil {
err500("can't convert URL query value: ", err, r)
}
query := fmt.Sprintf(`DELETE FROM relations WHERE userId="%d" AND friendId="%d"`,
user.(*auth.UserModel).Id,
did,
)
_, err = app.DB.Exec(query)
if err != nil {
err500("can't remove relation from DB: ", err, r)
}
r.Redirect("/")
}
func str2Time(s string, r render.Render) time.Time {
t, err := time.Parse("2006-01-02 15:04:05", s)
if err != nil {

View File

@ -2,18 +2,18 @@ package models
type Configuration struct {
Server Server
DSN DSN
DSN DSN
}
type Server struct {
Address string
Port string
Address string
Port string
}
type DSN struct {
Host string
Port string
User string
Pass string
Base string
}
Host string
Port string
User string
Pass string
Base string
}

View File

@ -1,14 +1,56 @@
<!DOCTYPE html>
<html>
<body>
<h2> Your account data</h2>
<p> Hello <b>{{ .Name }} {{ .Surname }}</b></p>
<p>You gender is <b>{{ .Gender }}</b></p>
<p>You <b>{{ .YearsOld }}</b> years old</p>
<p>You now live in <b>{{ .City }}</b></p>
<p>You interests is: <b>{{ .Interests }}</b></p>
<head>
<style>
table {
border-collapse: collapse;
border: 1px solid black;
width: 100%;
background-color: azure;
}
table th {
border: 1px solid black;
background-color: aquamarine;
}
table td {
border: 1px solid black;
}
</style>
</head>
<body>
<h2> Your account data</h2>
<p> Hello <b>{{ .user.Name }} {{ .user.Surname }}</b></p>
<p>You gender is <b>{{ .user.Gender }}</b></p>
<p>You <b>{{ .user.YearsOld }}</b> years old</p>
<p>You now live in <b>{{ .user.City }}</b></p>
<p>You interests is: <b>{{ .user.Interests }}</b></p>
<input type="button" onclick="location.href='/list';" value="User list" />
<input type="button" onclick="location.href='/logout';" value="Logout" /><br />
</body>
<h2> You have friends:</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Years Old</th>
<th>Gender</th>
<th>City</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{{ range $value:=.table }}
<tr>
<td><a>{{ $value.Name }} {{ $value.Surname }}</a></td>
<td><a>{{ $value.YearsOld }}</a></td>
<td><a>{{ $value.Gender }}</a></td>
<td><a>{{ $value.City }}</a></td>
<td><a href="/unsubscribe?id={{ $value.Id }}">Unsubscribe</a></td>
</tr>
{{ end }}
</tbody>
</table>
<h2>Available actions:</h2>
<input type="button" onclick="location.href='/list';" value="User list" />
<input type="button" onclick="location.href='/logout';" value="Logout" /><br />
</body>
</html>

View File

@ -26,6 +26,7 @@
<th>Years Old</th>
<th>Gender</th>
<th>City</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@ -35,10 +36,13 @@
<td><a>{{ $value.YearsOld }}</a></td>
<td><a>{{ $value.Gender }}</a></td>
<td><a>{{ $value.City }}</a></td>
<td><a href="/subscribe?id={{ $value.Id }}">Subscribe</a></td>
</tr>
{{ end }}
</tbody>
</table>
<h2>Available actions:</h2>
<input type="button" onclick="location.href='/';" value="Home" />
</body>
</html>