main.go (5359B)
1 package main 2 3 import ( 4 "database/sql" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "os" 9 "strconv" 10 "time" 11 12 "github.com/gofiber/fiber/v2" 13 _ "github.com/mattn/go-sqlite3" 14 ) 15 16 var epoch int = 1630000000 17 var SQLITE3 string = "sqlite3" 18 var DB_NAME string = "./twtr.db" 19 var MYPASS = "SOME_PASSPHRASE" 20 21 type twtrDBres struct { 22 ID int 23 TWEET string 24 UNIXTIMESTAMP int 25 } 26 27 func main() { 28 updateSite() 29 app := fiber.New() 30 31 app.Get("/", getAllTwts) 32 33 app.Post("/new", postTwt) 34 35 app.Delete("/x/:id", delTwt) 36 37 log.Fatal(app.Listen(":3000")) 38 } 39 40 func getAllTwts(c *fiber.Ctx) error { 41 db, err := sql.Open(SQLITE3, DB_NAME) 42 defer db.Close() 43 if err != nil { 44 fmt.Fprintln(os.Stderr, err) 45 return c.Status(400).JSON(&fiber.Map{ 46 "error": "Error occurred.", 47 }) 48 } 49 rows, err := db.Query("SELECT * FROM twts ORDER BY ID DESC") 50 if err != nil { 51 fmt.Fprintln(os.Stderr, err) 52 return c.Status(400).JSON(&fiber.Map{ 53 "error": "Error occurred.", 54 }) 55 } 56 var res []twtrDBres 57 for rows.Next() { 58 var ID int 59 var TWEET string 60 var UNIXTIMESTAMP int 61 err = rows.Scan(&ID, &TWEET, &UNIXTIMESTAMP) 62 if err != nil { 63 fmt.Fprintln(os.Stderr, err) 64 return c.Status(400).JSON(&fiber.Map{ 65 "error": "Error occurred.", 66 }) 67 } 68 res = append(res, twtrDBres{ID, TWEET, (UNIXTIMESTAMP + epoch) * 1000}) 69 } 70 return c.JSON(&fiber.Map{ 71 "res": res, 72 }) 73 } 74 75 func delTwt(c *fiber.Ctx) error { 76 req := map[string]string{} 77 c.BodyParser(&req) 78 passphrase := req["passphrase"] 79 id, err := strconv.Atoi(c.Params("id")) 80 if err != nil { 81 fmt.Fprintln(os.Stderr, err) 82 return c.Status(400).JSON(&fiber.Map{ 83 "error": err, 84 }) 85 } 86 if passphrase != MYPASS { 87 fmt.Fprintln(os.Stderr, "Invalid passphrase.") 88 return c.Status(403).JSON(&fiber.Map{ 89 "error": "Invalid passphrase", 90 }) 91 } 92 db, err := sql.Open(SQLITE3, DB_NAME) 93 defer db.Close() 94 if err != nil { 95 fmt.Fprintln(os.Stderr, err) 96 return c.Status(400).JSON(&fiber.Map{ 97 "error": "Error occurred.", 98 }) 99 } 100 stmt, err := db.Prepare("DELETE FROM twts WHERE ID = ?") 101 if err != nil { 102 fmt.Fprintln(os.Stderr, err) 103 return c.Status(400).JSON(&fiber.Map{ 104 "error": "Error occurred.", 105 }) 106 } 107 _, err = stmt.Exec(id) 108 if err != nil { 109 fmt.Fprintln(os.Stderr, err) 110 return c.Status(400).JSON(&fiber.Map{ 111 "error": "Error occurred.", 112 }) 113 } 114 updateSite() 115 return c.SendString("DELETE request successful.") 116 } 117 func postTwt(c *fiber.Ctx) error { 118 req := map[string]string{} 119 c.BodyParser(&req) 120 content := req["content"] 121 passphrase := req["passphrase"] 122 if content == "" { 123 fmt.Fprintln(os.Stderr, "Missing content in POST method.") 124 return c.Status(400).JSON(&fiber.Map{ 125 "error": "Missing content in POST method.", 126 }) 127 } 128 if passphrase != MYPASS { 129 fmt.Fprintln(os.Stderr, "Invalid passphrase.") 130 return c.Status(403).JSON(&fiber.Map{ 131 "error": "Invalid passphrase", 132 }) 133 } 134 right_now := int(time.Now().UnixMilli()/1000) - epoch 135 db, err := sql.Open(SQLITE3, DB_NAME) 136 defer db.Close() 137 if err != nil { 138 fmt.Fprintln(os.Stderr, err) 139 return c.Status(400).JSON(&fiber.Map{ 140 "error": "Error occurred.", 141 }) 142 } 143 stmt, err := db.Prepare("INSERT INTO twts (TWEET, UNIXTIMESTAMP) VALUES(?, ?)") 144 if err != nil { 145 fmt.Fprintln(os.Stderr, err) 146 return c.Status(400).JSON(&fiber.Map{ 147 "error": "Error occurred.", 148 }) 149 } 150 _, err = stmt.Exec(content, right_now) 151 if err != nil { 152 fmt.Fprintln(os.Stderr, err) 153 return c.Status(400).JSON(&fiber.Map{ 154 "error": "Error occurred.", 155 }) 156 } 157 updateSite() 158 return c.SendString("POST request successful.") 159 } 160 func updateSite() { 161 os.Remove("dst/index.html") 162 copyHead() 163 fillTwts() 164 copyFooter() 165 } 166 167 func copyHead() { 168 bytesRead, err := ioutil.ReadFile("src/_header.html") 169 if err != nil { 170 fmt.Fprintln(os.Stderr, err) 171 return 172 } 173 err = ioutil.WriteFile("dst/index.html", bytesRead, 0644) 174 if err != nil { 175 fmt.Fprintln(os.Stderr, err) 176 return 177 } 178 } 179 func copyFooter() { 180 bytesRead, err := ioutil.ReadFile("src/_footer.html") 181 if err != nil { 182 fmt.Fprintln(os.Stderr, err) 183 os.Exit(1) 184 } 185 f, err := os.OpenFile("dst/index.html", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 186 defer f.Close() 187 if err != nil { 188 fmt.Fprintln(os.Stderr, err) 189 os.Exit(1) 190 } 191 f.WriteString(string(bytesRead)) 192 } 193 func fillTwts() { 194 twts := getTweets() 195 for _, elem := range twts { 196 friendlyDate := time.Unix(int64(elem.UNIXTIMESTAMP/1000), 0).Format(time.UnixDate) 197 id := strconv.Itoa(elem.ID) 198 div := ` 199 <div class="entry"> 200 <p>` + elem.TWEET + `</p> 201 <a href="#` + id + `" id="` + id + `"> 202 <small class="date">` + friendlyDate + `</small> 203 </a> 204 </div> 205 ` 206 f, err := os.OpenFile("dst/index.html", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 207 defer f.Close() 208 if err != nil { 209 fmt.Fprintln(os.Stderr, err) 210 os.Exit(1) 211 } 212 f.WriteString(div) 213 } 214 } 215 func getTweets() []twtrDBres { 216 db, err := sql.Open(SQLITE3, DB_NAME) 217 defer db.Close() 218 if err != nil { 219 fmt.Fprintln(os.Stderr, err) 220 os.Exit(1) 221 } 222 rows, err := db.Query("SELECT * FROM twts ORDER BY ID DESC") 223 if err != nil { 224 fmt.Fprintln(os.Stderr, err) 225 os.Exit(1) 226 } 227 var res []twtrDBres 228 for rows.Next() { 229 var ID int 230 var TWEET string 231 var UNIXTIMESTAMP int 232 err = rows.Scan(&ID, &TWEET, &UNIXTIMESTAMP) 233 if err != nil { 234 fmt.Fprintln(os.Stderr, err) 235 os.Exit(1) 236 } 237 res = append(res, twtrDBres{ID, TWEET, (UNIXTIMESTAMP + epoch) * 1000}) 238 } 239 return res 240 }