-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit a7b4105
Showing
36 changed files
with
1,593 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.DS_Store | ||
.idea/ | ||
chitchat.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
ChitChat | ||
|
||
The Go Web Programming example chitchat in chapter 2. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"Address": "0.0.0.0:8080", | ||
"ReadTimeout": 10, | ||
"WriteTimeout": 600, | ||
"Static": "public" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package data | ||
|
||
import ( | ||
"crypto/rand" | ||
"crypto/sha1" | ||
"database/sql" | ||
"fmt" | ||
_ "github.com/lib/pq" | ||
"log" | ||
) | ||
|
||
var Db *sql.DB | ||
|
||
const ( | ||
hostname = "localhost" | ||
hostPort = 5432 | ||
username = "postgres" | ||
password = "hellopg" | ||
databaseName = "chitchat" | ||
) | ||
|
||
var pgConStr = fmt.Sprintf("port=%d host=%s user=%s "+ | ||
"password=%s dbname=%s sslmode=disable", | ||
hostPort, hostname, username, password, databaseName) | ||
|
||
func init() { | ||
|
||
var err error | ||
Db, err = sql.Open("postgres", pgConStr) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
return | ||
} | ||
|
||
// create a random UUID with from RFC 4122 | ||
// adapted from http://github.com/nu7hatch/gouuid | ||
func createUUID() (uuid string) { | ||
u := new([16]byte) | ||
_, err := rand.Read(u[:]) | ||
if err != nil { | ||
log.Fatalln("Cannot generate UUID", err) | ||
} | ||
|
||
// 0x40 is reserved variant from RFC 4122 | ||
u[8] = (u[8] | 0x40) & 0x7F | ||
// Set the four most significant bits (bits 12 through 15) of the | ||
// time_hi_and_version field to the 4-bit version number. | ||
u[6] = (u[6] & 0xF) | (0x4 << 4) | ||
uuid = fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) | ||
return | ||
} | ||
|
||
// Encrypt hash plaintext with SHA-1 | ||
func Encrypt(plaintext string) (cryptext string) { | ||
cryptext = fmt.Sprintf("%x", sha1.Sum([]byte(plaintext))) | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
drop table posts; | ||
drop table threads; | ||
drop table sessions; | ||
drop table users; | ||
|
||
|
||
create table users | ||
( | ||
id serial primary key, | ||
uuid varchar(64) not null unique, | ||
name varchar(255), | ||
email varchar(255) not null unique, | ||
password varchar(255) not null, | ||
created_at timestamp not null | ||
); | ||
|
||
create table sessions | ||
( | ||
id serial primary key, | ||
uuid varchar(64) not null unique, | ||
email varchar(255), | ||
user_id integer references users (id), | ||
created_at timestamp not null | ||
); | ||
|
||
create table threads | ||
( | ||
id serial primary key, | ||
uuid varchar(64) not null unique, | ||
topic text, | ||
user_id integer references users (id), | ||
created_at timestamp not null | ||
); | ||
|
||
create table posts | ||
( | ||
id serial primary key, | ||
uuid varchar(64) not null unique, | ||
body text, | ||
user_id integer references users (id), | ||
thread_id integer references threads (id), | ||
created_at timestamp not null | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package data | ||
|
||
import ( | ||
"time" | ||
) | ||
|
||
type Thread struct { | ||
Id int | ||
Uuid string | ||
Topic string | ||
UserId int | ||
CreatedAt time.Time | ||
} | ||
|
||
type Post struct { | ||
Id int | ||
Uuid string | ||
Body string | ||
UserId int | ||
ThreadId int | ||
CreatedAt time.Time | ||
} | ||
|
||
// CreatedAtDate format the CreatedAt date to display nicely on the screen | ||
func (thread *Thread) CreatedAtDate() string { | ||
return thread.CreatedAt.Format("Jan 2, 2006 at 3:04pm") | ||
} | ||
|
||
func (post *Post) CreatedAtDate() string { | ||
return post.CreatedAt.Format("Jan 2, 2006 at 3:04pm") | ||
} | ||
|
||
// NumReplies get the number of posts in a thread | ||
func (thread *Thread) NumReplies() (count int) { | ||
rows, err := Db.Query("SELECT count(*) FROM posts where thread_id = $1", thread.Id) | ||
if err != nil { | ||
return | ||
} | ||
for rows.Next() { | ||
if err = rows.Scan(&count); err != nil { | ||
return | ||
} | ||
} | ||
rows.Close() | ||
return | ||
} | ||
|
||
// Posts get posts to a thread | ||
func (thread *Thread) Posts() (posts []Post, err error) { | ||
rows, err := Db.Query("SELECT id, uuid, body, user_id, thread_id, created_at FROM posts where thread_id = $1", thread.Id) | ||
if err != nil { | ||
return | ||
} | ||
for rows.Next() { | ||
post := Post{} | ||
if err = rows.Scan(&post.Id, &post.Uuid, &post.Body, &post.UserId, &post.ThreadId, &post.CreatedAt); err != nil { | ||
return | ||
} | ||
posts = append(posts, post) | ||
} | ||
rows.Close() | ||
return | ||
} | ||
|
||
// CreateThread Create a new thread | ||
func (user *User) CreateThread(topic string) (conv Thread, err error) { | ||
statement := "insert into threads (uuid, topic, user_id, created_at) values ($1, $2, $3, $4) returning id, uuid, topic, user_id, created_at" | ||
stmt, err := Db.Prepare(statement) | ||
if err != nil { | ||
return | ||
} | ||
defer stmt.Close() | ||
// use QueryRow to return a row and scan the returned id into the Session struct | ||
err = stmt.QueryRow(createUUID(), topic, user.Id, time.Now()).Scan(&conv.Id, &conv.Uuid, &conv.Topic, &conv.UserId, &conv.CreatedAt) | ||
return | ||
} | ||
|
||
// CreatePost Create a new post to a thread | ||
func (user *User) CreatePost(conv Thread, body string) (post Post, err error) { | ||
statement := "insert into posts (uuid, body, user_id, thread_id, created_at) values ($1, $2, $3, $4, $5) returning id, uuid, body, user_id, thread_id, created_at" | ||
stmt, err := Db.Prepare(statement) | ||
if err != nil { | ||
return | ||
} | ||
defer stmt.Close() | ||
// use QueryRow to return a row and scan the returned id into the Session struct | ||
err = stmt.QueryRow(createUUID(), body, user.Id, conv.Id, time.Now()).Scan(&post.Id, &post.Uuid, &post.Body, &post.UserId, &post.ThreadId, &post.CreatedAt) | ||
return | ||
} | ||
|
||
// Threads Get all threads in the database and returns it | ||
func Threads() (threads []Thread, err error) { | ||
rows, err := Db.Query("SELECT id, uuid, topic, user_id, created_at FROM threads ORDER BY created_at DESC") | ||
if err != nil { | ||
return | ||
} | ||
for rows.Next() { | ||
conv := Thread{} | ||
if err = rows.Scan(&conv.Id, &conv.Uuid, &conv.Topic, &conv.UserId, &conv.CreatedAt); err != nil { | ||
return | ||
} | ||
threads = append(threads, conv) | ||
} | ||
rows.Close() | ||
return | ||
} | ||
|
||
// ThreadByUUID Get a thread by the UUID | ||
func ThreadByUUID(uuid string) (conv Thread, err error) { | ||
conv = Thread{} | ||
err = Db.QueryRow("SELECT id, uuid, topic, user_id, created_at FROM threads WHERE uuid = $1", uuid). | ||
Scan(&conv.Id, &conv.Uuid, &conv.Topic, &conv.UserId, &conv.CreatedAt) | ||
return | ||
} | ||
|
||
// User Get the user who started this thread | ||
func (thread *Thread) User() (user User) { | ||
user = User{} | ||
Db.QueryRow("SELECT id, uuid, name, email, created_at FROM users WHERE id = $1", thread.UserId). | ||
Scan(&user.Id, &user.Uuid, &user.Name, &user.Email, &user.CreatedAt) | ||
return | ||
} | ||
|
||
// User Get the user who wrote the post | ||
func (post *Post) User() (user User) { | ||
user = User{} | ||
Db.QueryRow("SELECT id, uuid, name, email, created_at FROM users WHERE id = $1", post.UserId). | ||
Scan(&user.Id, &user.Uuid, &user.Name, &user.Email, &user.CreatedAt) | ||
return | ||
} |
Oops, something went wrong.