Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
zwfang committed Oct 31, 2021
0 parents commit a7b4105
Show file tree
Hide file tree
Showing 36 changed files with 1,593 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.DS_Store
.idea/
chitchat.log
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ChitChat

The Go Web Programming example chitchat in chapter 2.
6 changes: 6 additions & 0 deletions config.json
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"
}
58 changes: 58 additions & 0 deletions data/data.go
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
}
43 changes: 43 additions & 0 deletions data/setup.sql
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
);
130 changes: 130 additions & 0 deletions data/thread.go
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
}
Loading

0 comments on commit a7b4105

Please sign in to comment.