6 changed files with 215 additions and 0 deletions
@ -0,0 +1,56 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"bufio" |
||||||
|
"os" |
||||||
|
) |
||||||
|
|
||||||
|
type TxtStore string |
||||||
|
|
||||||
|
func (t *TxtStore) GetGuestbook() (Guestbook, error) { |
||||||
|
var result Guestbook |
||||||
|
|
||||||
|
file, err := os.Open(string(*t)) |
||||||
|
if os.IsNotExist(err) { |
||||||
|
return result, nil |
||||||
|
} else if err != nil { |
||||||
|
return result, err |
||||||
|
} |
||||||
|
defer file.Close() |
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file) |
||||||
|
var comments []string |
||||||
|
|
||||||
|
for scanner.Scan() { |
||||||
|
comments = append([]string{scanner.Text()}, comments...) |
||||||
|
} |
||||||
|
|
||||||
|
err = scanner.Err() |
||||||
|
if err != nil { |
||||||
|
return result, err |
||||||
|
} |
||||||
|
|
||||||
|
result.Comments = comments |
||||||
|
result.Count = len(comments) |
||||||
|
|
||||||
|
return result, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (t *TxtStore) AddComment(comment string) error { |
||||||
|
if comment == "" { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
options := os.O_WRONLY | os.O_APPEND | os.O_CREATE |
||||||
|
file, err := os.OpenFile(string(*t), options, os.FileMode(0600)) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
_, err = file.WriteString(comment + "\n") |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
return file.Close() |
||||||
|
} |
||||||
|
After Width: | Height: | Size: 24 KiB |
@ -0,0 +1,27 @@ |
|||||||
|
<!doctype html> |
||||||
|
|
||||||
|
<html lang="ru"> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<title>Книга отзывов</title> |
||||||
|
<link rel="icon" type="image/png" sizes="256x256" href="/html/favicon.png"> |
||||||
|
<link rel="stylesheet" type="text/css" href="html/styles.css"> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
<div class="main"> |
||||||
|
<h1>Книга отзывов</h1> |
||||||
|
|
||||||
|
|
||||||
|
<form action="/new" method="POST"> |
||||||
|
<p>Всего записей - {{ .Count }}</p> |
||||||
|
<input type="text" name="comment" placeholder="Ваш отзыв..."> |
||||||
|
<input type="submit" value="Отправить"> |
||||||
|
</form> |
||||||
|
|
||||||
|
<ul> |
||||||
|
{{ range .Comments }}<li>{{ . }}</li>{{ end}} |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</body> |
||||||
|
</html> |
||||||
@ -0,0 +1,79 @@ |
|||||||
|
* { |
||||||
|
margin: 0; |
||||||
|
padding: 0; |
||||||
|
|
||||||
|
font-family: 'Raleway', serif; |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
padding: 1%; |
||||||
|
|
||||||
|
color: #2E3E50; |
||||||
|
background: #D8DDDD; |
||||||
|
|
||||||
|
text-align: center; |
||||||
|
letter-spacing: 1px; |
||||||
|
} |
||||||
|
|
||||||
|
.main { |
||||||
|
margin: auto; |
||||||
|
padding: 1% 2%; |
||||||
|
max-width: 800px; |
||||||
|
border-radius: 5px; |
||||||
|
background: #ECF0F1; |
||||||
|
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, .3); |
||||||
|
} |
||||||
|
|
||||||
|
form { |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
margin: 2% 0; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
form p { |
||||||
|
text-align: left; |
||||||
|
padding: 1%; |
||||||
|
font-size: 18px; |
||||||
|
} |
||||||
|
|
||||||
|
input { |
||||||
|
padding: 1%; |
||||||
|
border-radius: 4px; |
||||||
|
border: 1px solid #CCC; |
||||||
|
font-size: 18px; |
||||||
|
} |
||||||
|
|
||||||
|
input[type=text] { |
||||||
|
flex-grow: 1; |
||||||
|
|
||||||
|
margin: 0 .5%; |
||||||
|
} |
||||||
|
|
||||||
|
input[type=submit] { |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
|
||||||
|
input[type=submit]:hover { |
||||||
|
background-color: #D8DDDD; |
||||||
|
} |
||||||
|
|
||||||
|
h1 { |
||||||
|
font-family: 'Baloo Tamma', cursive; |
||||||
|
} |
||||||
|
|
||||||
|
li{ |
||||||
|
list-style-type: none; |
||||||
|
|
||||||
|
font-size: 18px; |
||||||
|
min-width: 24%; |
||||||
|
margin: 2% 0; |
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, .2); |
||||||
|
padding: 1% 2%; |
||||||
|
background: #FFF; |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
|
||||||
|
li:hover { |
||||||
|
box-shadow:0 5px 10px rgba(0, 0, 0, .15); |
||||||
|
} |
||||||
@ -0,0 +1,50 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"html/template" |
||||||
|
"log" |
||||||
|
"net/http" |
||||||
|
) |
||||||
|
|
||||||
|
type Guestbook struct { |
||||||
|
Comments []string |
||||||
|
Count int |
||||||
|
} |
||||||
|
|
||||||
|
func indexHandler(writer http.ResponseWriter, request *http.Request) { |
||||||
|
html, err := template.ParseFiles("html/index.html") |
||||||
|
check(err) |
||||||
|
|
||||||
|
store := TxtStore("comments.txt") |
||||||
|
guestbook, err := store.GetGuestbook() |
||||||
|
check(err) |
||||||
|
|
||||||
|
err = html.Execute(writer, guestbook) |
||||||
|
check(err) |
||||||
|
} |
||||||
|
|
||||||
|
func newHandler(writer http.ResponseWriter, request *http.Request) { |
||||||
|
comment := request.FormValue("comment") |
||||||
|
store := TxtStore("comments.txt") |
||||||
|
|
||||||
|
err := store.AddComment(comment) |
||||||
|
check(err) |
||||||
|
|
||||||
|
http.Redirect(writer, request, "/", http.StatusFound) |
||||||
|
} |
||||||
|
|
||||||
|
func main() { |
||||||
|
http.HandleFunc("/", indexHandler) |
||||||
|
http.HandleFunc("/new", newHandler) |
||||||
|
|
||||||
|
http.Handle("/html/", http.StripPrefix("/html/", http.FileServer(http.Dir("html")))) |
||||||
|
|
||||||
|
err := http.ListenAndServe("0.0.0.0:80", nil) |
||||||
|
log.Fatal(err) |
||||||
|
} |
||||||
|
|
||||||
|
func check(err error) { |
||||||
|
if err != nil { |
||||||
|
log.Fatal(err) |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue