From fcf98f7b02ae9a2488e51ec2eb37dfba253fe678 Mon Sep 17 00:00:00 2001 From: akuma06 Date: Thu, 4 May 2017 05:28:42 +0200 Subject: [PATCH] Added ORM Support, Models and cleaned up a bit the code Changing from plain sql queries to GORM for better maintenance and stability Use of Models for database tables and added JSON objects Cleaned a bit the code and added some comments in the files --- index.html | 2 +- main.go | 149 +++++++++++++++++--------------------------------- models.go | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 100 deletions(-) create mode 100644 models.go diff --git a/index.html b/index.html index e4588a1b..fb404775 100644 --- a/index.html +++ b/index.html @@ -91,7 +91,7 @@ Hash Links - {{ range .Records}} + {{ range .ListTorrents}} diff --git a/main.go b/main.go index e71417cc..89446fff 100644 --- a/main.go +++ b/main.go @@ -1,44 +1,34 @@ package main import ( - "database/sql" "encoding/json" "github.com/gorilla/mux" - _ "github.com/mattn/go-sqlite3" + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/sqlite" "html" "html/template" "log" "net/http" - "net/url" "strconv" "strings" "time" ) -var dbHandle *sql.DB +var db *gorm.DB var templates = template.Must(template.ParseFiles("index.html")) var debugLogger *log.Logger var trackers = "&tr=udp://zer0day.to:1337/announce&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://explodie.org:6969&tr=udp://tracker.opentrackr.org:1337&tr=udp://tracker.coppersurfer.tk:6969" -type Record struct { - Category string `json: "category"` - Records []Records `json: "records"` - QueryRecordCount int `json: "queryRecordCount"` - TotalRecordCount int `json: "totalRecordCount"` -} -type Records struct { - Id string `json: "id"` - Name string `json: "name"` - Status int `json: "status"` - Hash string `json: "hash"` - Magnet template.URL `json: "magnet"` -} +func getDBHandle() *gorm.DB { + dbInit, err := gorm.Open("sqlite3", "./nyaa.db") + + // Migrate the schema of Torrents + // dbInit.AutoMigrate(&Torrents{}) + // dbInit.AutoMigrate(&SubCategories{}) -func getDBHandle() *sql.DB { - db, err := sql.Open("sqlite3", "./nyaa.db") checkErr(err) - return db + return dbInit } func checkErr(err error) { @@ -52,28 +42,21 @@ func apiHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) page := vars["page"] pagenum, _ := strconv.Atoi(html.EscapeString(page)) - b := Record{Records: []Records{}} - rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*(pagenum-1)) - for rows.Next() { - var id, name, hash, magnet string - var status int - rows.Scan(&id, &name, &status, &hash) - magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + trackers - res := Records{ - Id: id, - Name: name, - Status: status, - Hash: hash, - Magnet: safe(magnet)} + b := CategoryJson{Torrents: []TorrentsJson{}} + maxPerPage := 50 + nbTorrents := 0 - b.Records = append(b.Records, res) + torrents := getAllTorrents(maxPerPage, maxPerPage*(pagenum-1)) + for i, _ := range torrents { + nbTorrents++ + res := torrents[i].toJson() + b.Torrents = append(b.Torrents, res) } - b.QueryRecordCount = 50 - b.TotalRecordCount = 1473098 - rows.Close() + b.QueryRecordCount = maxPerPage + b.TotalRecordCount = nbTorrents w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(b) + err := json.NewEncoder(w).Encode(b) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -84,26 +67,14 @@ func singleapiHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] - b := Record{Records: []Records{}} - rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents where torrent_id = ? ORDER BY torrent_id DESC", html.EscapeString(id)) - for rows.Next() { - var id, name, hash, magnet string - var status int - rows.Scan(&id, &name, &status, &hash) - magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + trackers - res := Records{ - Id: id, - Name: name, - Status: status, - Hash: hash, - Magnet: safe(magnet)} + b := CategoryJson{Torrents: []TorrentsJson{}} - b.Records = append(b.Records, res) + torrent, err := getTorrentById(id) + res := torrent.toJson() + b.Torrents = append(b.Torrents, res) - } b.QueryRecordCount = 1 - b.TotalRecordCount = 1473098 - rows.Close() + b.TotalRecordCount = 1 w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(b) @@ -123,39 +94,28 @@ func searchHandler(w http.ResponseWriter, r *http.Request) { maxPerPage = 50 // default Value maxPerPage } pagenum, _ := strconv.Atoi(html.EscapeString(page)) - param1 := r.URL.Query().Get("q") + searchQuery := r.URL.Query().Get("q") cat := r.URL.Query().Get("c") - param2 := strings.Split(cat, "_")[0] - param3 := strings.Split(cat, "_")[1] + searchCatId := html.EscapeString(strings.Split(cat, "_")[0]) + searchSubCatId := html.EscapeString(strings.Split(cat, "_")[1]) nbTorrents := 0 - b := Record{Category: cat, Records: []Records{}} - rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents "+ - "where torrent_name LIKE ? AND category_id LIKE ? AND sub_category_id LIKE ? "+ - "ORDER BY torrent_id DESC LIMIT ? offset ?", - "%"+html.EscapeString(param1)+"%", html.EscapeString(param2)+"%", html.EscapeString(param3)+"%", maxPerPage, maxPerPage*(pagenum-1)) - for rows.Next() { - nbTorrents++ - var id, name, hash, magnet string - var status int - rows.Scan(&id, &name, &status, &hash) - magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + trackers - res := Records{ - Id: id, - Name: name, - Status: status, - Hash: hash, - Magnet: safe(magnet)} + b := []TorrentsJson{} - b.Records = append(b.Records, res) + torrents := getTorrents(createWhereParams("torrent_name LIKE ? AND category_id LIKE ? AND sub_category_id LIKE ?", "%"+searchQuery+"%", searchCatId+"%", searchSubCatId+"%"), maxPerPage, maxPerPage*(pagenum-1)) + + for i, _ := range torrents { + nbTorrents++ + res := torrents[i].toJson() + + b = append(b, res) } - b.QueryRecordCount = maxPerPage - b.TotalRecordCount = nbTorrents - rows.Close() - err = templates.ExecuteTemplate(w, "index.html", &b) + htv := HomeTemplateVariables{b, getAllCategories(false), searchQuery, cat, maxPerPage, nbTorrents} + + err := templates.ExecuteTemplate(w, "index.html", htv) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } @@ -176,28 +136,19 @@ func rootHandler(w http.ResponseWriter, r *http.Request) { nbTorrents := 0 pagenum, _ := strconv.Atoi(html.EscapeString(page)) - b := Record{Category: "_", Records: []Records{}} - rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT ? offset ?", maxPerPage, maxPerPage*(pagenum-1)) - for rows.Next() { + b := []TorrentsJson{} + torrents := getAllTorrents(maxPerPage, maxPerPage*(pagenum-1)) + for i, _ := range torrents { nbTorrents++ - var id, name, hash, magnet string - var status int - rows.Scan(&id, &name, &status, &hash) - magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + trackers - res := Records{ - Id: id, - Name: name, - Status: status, - Hash: hash, - Magnet: safe(magnet)} + res := torrents[i].toJson() - b.Records = append(b.Records, res) + b = append(b, res) } - b.QueryRecordCount = maxPerPage - b.TotalRecordCount = nbTorrents - rows.Close() - err = templates.ExecuteTemplate(w, "index.html", &b) + + htv := HomeTemplateVariables{b, getAllCategories(false), "", "_", maxPerPage, nbTorrents} + + err := templates.ExecuteTemplate(w, "index.html", htv) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } @@ -206,7 +157,7 @@ func rootHandler(w http.ResponseWriter, r *http.Request) { func main() { - dbHandle = getDBHandle() + db = getDBHandle() router := mux.NewRouter() cssHandler := http.FileServer(http.Dir("./css/")) diff --git a/models.go b/models.go new file mode 100644 index 00000000..0a3c9981 --- /dev/null +++ b/models.go @@ -0,0 +1,157 @@ +package main + +import ( + "github.com/jinzhu/gorm" + "html" + "html/template" + "strconv" + "net/url" + "errors" +) + +type Categories struct { + Category_id int + Category_name string + Torrents []Torrents `gorm:"ForeignKey:category_id;AssociationForeignKey:category_id"` + Sub_category []Sub_Categories `gorm:"ForeignKey:category_id;AssociationForeignKey:parent_id"` +} + +type Sub_Categories struct { + Sub_category_id int + Sub_category_name string + Parent_id int + Torrents []Torrents `gorm:"ForeignKey:sub_category_id;AssociationForeignKey:sub_category_id"` +} + +type Torrents struct { + gorm.Model + Id int `gorm:"column:torrent_id"` + Name string `gorm:"column:torrent_name"` + Category_id int `gorm:"column:category_id"` + Sub_category_id int + Status int `gorm:"column:status_id"` + Hash string `gorm:"column:torrent_hash"` + Categories Categories `gorm:"ForeignKey:category_id;AssociationForeignKey:category_id"` + Sub_Categories Sub_Categories `gorm:"ForeignKey:sub_category_id;AssociationForeignKey:sub_category_id"` +} + + + +/* We need JSON Object instead because of Magnet URL that is not in the database but generated dynamically +-------------------------------------------------------------------------------------------------------------- +JSON Models Oject +-------------------------------------------------------------------------------------------------------------- +*/ + +type CategoryJson struct { + Category string `json: "category"` + Torrents []TorrentsJson `json: "torrents"` + QueryRecordCount int `json: "queryRecordCount"` + TotalRecordCount int `json: "totalRecordCount"` +} + +type TorrentsJson struct { + Id string `json: "id"` // Is there a need to put the ID? + Name string `json: "name"` + Status int `json: "status"` + Hash string `json: "hash"` + Magnet template.URL `json: "magnet"` +} + +type WhereParams struct { + conditions string // Ex : name LIKE ? AND category_id LIKE ? + params []interface{} +} + + +/* Each Page should have an object to pass to their own template */ + +type HomeTemplateVariables struct { + ListTorrents []TorrentsJson + ListCategories []Categories + Query string + Category string + QueryRecordCount int + TotalRecordCount int +} + + +/* Function to interact with Models + * + * Get the torrents with where clause + * +*/ + +func getTorrentById(id string) (Torrents, error) { + var torrent Torrents + + if db.Order("torrent_id DESC").First(&torrent, "id = ?", html.EscapeString(id)).RecordNotFound() { + return torrent, errors.New("Article is not found.") + } + + return torrent, nil +} + +func getTorrents(parameters WhereParams, limit int, offset int) ([]Torrents) { + var torrents []Torrents + db.Limit(limit).Offset(offset).Order("torrent_id DESC").Where(parameters.conditions, parameters.params...).Preload("Categories").Preload("Sub_Categories").Find(&torrents) + return torrents +} + +func getTorrentsDB(parameters WhereParams) ([]Torrents) { + var torrents []Torrents + db.Where(parameters.conditions, parameters.params...).Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents) + return torrents +} + +/* Function to get all torrents +*/ + +func getAllTorrents(limit int, offset int) ([]Torrents) { + var torrents []Torrents + db.Model(&torrents).Limit(limit).Offset(offset).Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents) + + return torrents +} + +func getAllTorrentsDB() ([]Torrents) { + var torrents []Torrents + db.Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents) + return torrents +} + +/* Function to get all categories with/without torrents (bool) +*/ +func getAllCategories(populatedWithTorrents bool) ([]Categories) { + var categories []Categories + if populatedWithTorrents { + db.Preload("Torrents").Preload("Sub_Categories").Find(&categories) + } else { + db.Preload("Sub_Categories").Find(&categories) + } + return categories +} + + + +func (t *Torrents) toJson() (TorrentsJson) { + magnet := "magnet:?xt=urn:btih:" + t.Hash + "&dn=" + url.QueryEscape(t.Name) + trackers + res := TorrentsJson{ + Id: strconv.Itoa(t.Id), + Name: t.Name, + Status: t.Status, + Hash: t.Hash, + Magnet: safe(magnet)} + return res; +} + +func createWhereParams(conditions string, params ...string) (WhereParams) { + whereParams := WhereParams{} + whereParams.conditions = conditions + for i, _ := range params { + whereParams.params = append(whereParams.params, params[i]) + } + + return whereParams +} +/* Complete the functions when necessary... */ \ No newline at end of file