storage.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. package storage
  2. import (
  3. "database/sql"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "log"
  8. "mime/multipart"
  9. "os"
  10. "path"
  11. "strings"
  12. "time"
  13. "git.aetherial.dev/aeth/keiji/pkg/env"
  14. "github.com/google/uuid"
  15. )
  16. const TECHNICAL = "technical"
  17. const CONFIGURATION = "configuration"
  18. const BLOG = "blog"
  19. const CREATIVE = "creative"
  20. const DIGITAL_ART = "digital_art"
  21. const MISC_ASSET = "misc_asset"
  22. const HOMEPAGE = "homepage"
  23. var Topics = []string{
  24. TECHNICAL,
  25. BLOG,
  26. CREATIVE,
  27. HOMEPAGE,
  28. }
  29. var ImageCategories = []string{
  30. MISC_ASSET,
  31. DIGITAL_ART,
  32. }
  33. type DatabaseSchema struct {
  34. // Gotta figure out what this looks like
  35. // so that the ExtractAll() function gets
  36. // all of the data from the database
  37. }
  38. type MenuElement struct {
  39. Png string `json:"png"`
  40. Category string `json:"category"`
  41. MenuLinks []LinkPair `json:"menu_links"`
  42. }
  43. type AdminPage struct {
  44. Tables map[string][]TableData `json:"tables"`
  45. }
  46. type TableData struct { // TODO: add this to the database io interface
  47. DisplayName string `json:"display_name"`
  48. Link string `json:"link"`
  49. }
  50. type LinkPair struct {
  51. Link string `json:"link"`
  52. Text string `json:"text"`
  53. }
  54. type NavBarItem struct {
  55. Png []byte `json:"png"`
  56. File *multipart.FileHeader `form:"file"`
  57. Link string `json:"link" form:"link"`
  58. Redirect string `json:"redirect" form:"redirect"`
  59. }
  60. type Asset struct {
  61. Name string
  62. Data []byte
  63. }
  64. type Identifier string
  65. type Document struct {
  66. Row int
  67. Ident Identifier `json:"id"`
  68. Title string `json:"title"`
  69. Created string `json:"created"`
  70. Body string `json:"body"`
  71. Category string `json:"category"`
  72. Sample string `json:"sample"`
  73. }
  74. /*
  75. Truncates a text post into a 256 character long 'sample' for displaying posts
  76. */
  77. func (d *Document) MakeSample() string {
  78. t := strings.Split(d.Body, "")
  79. var sample []string
  80. if len(d.Body) < 256 {
  81. return d.Body
  82. }
  83. for i := 0; i < 256; i++ {
  84. sample = append(sample, t[i])
  85. }
  86. sample = append(sample, " ...")
  87. return strings.Join(sample, "")
  88. }
  89. type Image struct {
  90. Ident Identifier `json:"identifier"`
  91. Location string
  92. Title string `json:"title" form:"title"`
  93. File *multipart.FileHeader `form:"file"`
  94. Desc string `json:"description" form:"description"`
  95. Created string
  96. Category string `json:"category" form:"category"`
  97. Data []byte
  98. }
  99. type Tool struct {
  100. Ident Identifier
  101. Name string
  102. Desc string
  103. ImageLink string
  104. UserInterfaceLink string
  105. OsPath string
  106. }
  107. type DocumentIO interface {
  108. GetDocument(id Identifier) (Document, error)
  109. GetImage(id Identifier) (Image, error)
  110. GetAllImages() []Image
  111. GetImagesByCategory(category string) []Image
  112. UpdateDocument(doc Document) error
  113. DeleteDocument(id Identifier) error
  114. DeleteNavbarItem(id Identifier) error
  115. AddDocument(doc Document) (Identifier, error)
  116. AddImage(data []byte, title, desc, category string) (Identifier, error)
  117. AddAsset(name string, data []byte) error
  118. AddAdminTableEntry(TableData, string) error
  119. AddNavbarItem(NavBarItem) error
  120. AddMenuItem(LinkPair) error
  121. GetByCategory(category string) []Document
  122. AllDocuments() []Document
  123. GetDropdownElements() []LinkPair
  124. GetNavBarLinks() []NavBarItem
  125. GetAssets() []Asset
  126. GetAdminTables() AdminPage
  127. GetTools() []Tool
  128. }
  129. var (
  130. ErrDuplicate = errors.New("record already exists")
  131. ErrNotExists = errors.New("row not exists")
  132. ErrUpdateFailed = errors.New("update failed")
  133. ErrDeleteFailed = errors.New("delete failed")
  134. )
  135. type SQLiteRepo struct {
  136. db *sql.DB
  137. imageIO ImageIO
  138. }
  139. type ImageIO interface {
  140. Put([]byte, Identifier) error
  141. Get(Identifier) ([]byte, error)
  142. }
  143. type FilesystemImageIO struct {
  144. RootDir string
  145. }
  146. /*
  147. create a new FilesystemImageIO struct
  148. */
  149. func MustNewFilesystemImageIO(path string) FilesystemImageIO {
  150. var filemode os.FileMode
  151. filemode = 0775
  152. err := os.MkdirAll(path, filemode)
  153. if err != nil {
  154. log.Fatalf("Error creating path: '%s' with permissions: '%d'. Error: %s\n", path, filemode, err.Error())
  155. }
  156. return FilesystemImageIO{RootDir: path}
  157. }
  158. /*
  159. Put a data blob on the filesystem
  160. :param b: the
  161. */
  162. func (f FilesystemImageIO) Put(b []byte, id Identifier) error {
  163. fh, err := os.OpenFile(path.Join(f.RootDir, string(id)), os.O_CREATE|os.O_RDWR, os.ModePerm)
  164. if err != nil {
  165. return err
  166. }
  167. defer fh.Close()
  168. _, err = fh.Write(b)
  169. if err != nil {
  170. return err
  171. }
  172. return nil
  173. }
  174. /*
  175. Get a data blob from the filesystem
  176. :param id: the identifier of the image to retrieve
  177. */
  178. func (f FilesystemImageIO) Get(id Identifier) ([]byte, error) {
  179. fh, err := os.Open(path.Join(f.RootDir, string(id)))
  180. if err != nil {
  181. return nil, err
  182. }
  183. b, err := io.ReadAll(fh)
  184. if err != nil {
  185. return nil, err
  186. }
  187. return b, nil
  188. }
  189. // Instantiate a new SQLiteRepo struct
  190. func NewSQLiteRepo(db *sql.DB, imgIo ImageIO) *SQLiteRepo {
  191. return &SQLiteRepo{
  192. db: db,
  193. imageIO: imgIo,
  194. }
  195. }
  196. // Creates a new SQL table for text posts
  197. func (r *SQLiteRepo) Migrate(seedQueries []string) error {
  198. for i := range seedQueries {
  199. _, err := r.db.Exec(seedQueries[i])
  200. if err != nil {
  201. return err
  202. }
  203. }
  204. return nil
  205. }
  206. // Gets the tool table from the database
  207. func (s *SQLiteRepo) GetTools() []Tool {
  208. rows, err := s.db.Query("SELECT * FROM tools")
  209. var toolItems []Tool
  210. defer rows.Close()
  211. for rows.Next() {
  212. var id int
  213. var item Tool
  214. err = rows.Scan(&id, &item.Ident, &item.Name, &item.Desc, &item.ImageLink, &item.UserInterfaceLink, &item.OsPath)
  215. if err != nil {
  216. log.Fatal(err)
  217. }
  218. toolItems = append(toolItems, item)
  219. }
  220. return toolItems
  221. }
  222. /*
  223. Get all dropdown menu elements. Returns a list of LinkPair structs with the text and redirect location
  224. */
  225. func (s *SQLiteRepo) GetDropdownElements() []LinkPair {
  226. rows, err := s.db.Query("SELECT * FROM menu")
  227. var menuItems []LinkPair
  228. defer rows.Close()
  229. for rows.Next() {
  230. var id int
  231. var item LinkPair
  232. err = rows.Scan(&id, &item.Link, &item.Text)
  233. if err != nil {
  234. log.Fatal(err)
  235. }
  236. menuItems = append(menuItems, item)
  237. }
  238. return menuItems
  239. }
  240. /*
  241. Retrieve a dropdown element by its text name on the UI
  242. */
  243. func (s *SQLiteRepo) GetMenuItemByName(link, text string) (LinkPair, bool) {
  244. fmt.Printf("From GetMenuItemByName: Link: %s Text: %s\n", link, text)
  245. rows := s.db.QueryRow("SELECT * FROM menu WHERE link = ? AND text = ?", link, text)
  246. var item LinkPair
  247. var id int
  248. err := rows.Scan(&id, &item.Link, &item.Text)
  249. if err != nil {
  250. if errors.Is(err, sql.ErrNoRows) {
  251. return item, false
  252. } else {
  253. return item, false
  254. }
  255. }
  256. return item, true
  257. }
  258. // get Admin table entry by its display name, link, and category.
  259. func (s *SQLiteRepo) GetAdminTableEntry(displayName, link, category string) (TableData, bool) {
  260. rows := s.db.QueryRow("SELECT * FROM admin WHERE display_name = ? AND link = ? AND category = ?", displayName, link, category)
  261. var item TableData
  262. var id int
  263. err := rows.Scan(&id, &item.DisplayName, &item.Link, &category)
  264. if err != nil {
  265. if errors.Is(err, sql.ErrNoRows) {
  266. return item, false
  267. }
  268. log.Printf("Error getting admin table entry: %s", err.Error())
  269. return item, false
  270. }
  271. return item, true
  272. }
  273. // get navbar entry.
  274. func (s *SQLiteRepo) GetNavbarLink(link, redirect string) (NavBarItem, bool) {
  275. rows := s.db.QueryRow("SELECT * FROM navbar WHERE link = ? AND redirect = ?", link, redirect)
  276. var item NavBarItem
  277. var id int
  278. err := rows.Scan(&id, &item.Png, &item.Link, &item.Redirect)
  279. if err != nil {
  280. if errors.Is(err, sql.ErrNoRows) {
  281. return item, false
  282. }
  283. log.Printf("Error scanning for item: %s", err.Error())
  284. return item, false
  285. }
  286. return item, true
  287. }
  288. // get an asset from the store
  289. func (s *SQLiteRepo) GetAsset(name string) (Asset, bool) {
  290. rows := s.db.QueryRow("SELECT * FROM assets WHERE name = ?", name)
  291. var item Asset
  292. var id int
  293. err := rows.Scan(&id, &item.Name, &item.Data)
  294. if err != nil {
  295. if errors.Is(err, sql.ErrNoRows) {
  296. return item, false
  297. }
  298. log.Printf("Error getting asset: %s", err.Error())
  299. return item, false
  300. }
  301. return item, true
  302. }
  303. /*
  304. Get all nav bar items. Returns a list of NavBarItem structs with the png data, the file name, and the redirect location of the icon
  305. /*
  306. Get all nav bar items. Returns a list of NavBarItem structs with the png data, the file name, and the redirect location of the icon
  307. */
  308. func (s *SQLiteRepo) GetNavBarLinks() []NavBarItem {
  309. rows, err := s.db.Query("SELECT * FROM navbar")
  310. var navbarItems []NavBarItem
  311. defer rows.Close()
  312. for rows.Next() {
  313. var item NavBarItem
  314. var id int
  315. err = rows.Scan(&id, &item.Png, &item.Link, &item.Redirect)
  316. if err != nil {
  317. log.Fatal(err)
  318. }
  319. navbarItems = append(navbarItems, item)
  320. }
  321. return navbarItems
  322. }
  323. /*
  324. get all assets from the asset table
  325. */
  326. func (s *SQLiteRepo) GetAssets() []Asset {
  327. rows, err := s.db.Query("SELECT * FROM assets")
  328. var assets []Asset
  329. defer rows.Close()
  330. for rows.Next() {
  331. var item Asset
  332. var id int
  333. err = rows.Scan(&id, &item.Name, &item.Data)
  334. if err != nil {
  335. log.Fatal(err)
  336. }
  337. assets = append(assets, item)
  338. }
  339. return assets
  340. }
  341. /*
  342. get all assets from the asset table
  343. */
  344. func (s *SQLiteRepo) GetAdminTables() AdminPage {
  345. rows, err := s.db.Query("SELECT * FROM admin")
  346. adminPage := AdminPage{Tables: map[string][]TableData{}}
  347. defer rows.Close()
  348. for rows.Next() {
  349. var item TableData
  350. var id int
  351. var category string
  352. err = rows.Scan(&id, &item.DisplayName, &item.Link, &category)
  353. if err != nil {
  354. log.Fatal(err)
  355. }
  356. adminPage.Tables[category] = append(adminPage.Tables[category], item)
  357. }
  358. return adminPage
  359. }
  360. /*
  361. Retrieve a document from the sqlite db
  362. :param id: the Identifier of the post
  363. */
  364. func (s *SQLiteRepo) GetDocument(id Identifier) (Document, error) {
  365. row := s.db.QueryRow("SELECT * FROM posts WHERE id = ?", id)
  366. var post Document
  367. var rowNum int
  368. if err := row.Scan(&rowNum, &post.Ident, &post.Title, &post.Created, &post.Body, &post.Category, &post.Sample); err != nil {
  369. if errors.Is(err, sql.ErrNoRows) {
  370. return post, ErrNotExists
  371. }
  372. return post, err
  373. }
  374. return post, nil
  375. }
  376. /*
  377. Get all documents by category
  378. :param category: the category to retrieve all docs from
  379. */
  380. func (s *SQLiteRepo) GetByCategory(category string) []Document {
  381. rows, err := s.db.Query("SELECT * FROM posts WHERE category = ?", category)
  382. if err != nil {
  383. log.Fatal(err)
  384. }
  385. var docs []Document
  386. defer rows.Close()
  387. for rows.Next() {
  388. var doc Document
  389. err := rows.Scan(&doc.Row, &doc.Ident, &doc.Title, &doc.Created, &doc.Body, &doc.Category, &doc.Sample)
  390. if err != nil {
  391. log.Fatal(err)
  392. }
  393. docs = append(docs, doc)
  394. }
  395. err = rows.Err()
  396. if err != nil {
  397. log.Fatal(err)
  398. }
  399. return docs
  400. }
  401. /*
  402. get image data from the images table
  403. :param id: the serial identifier of the post
  404. */
  405. func (s *SQLiteRepo) GetImage(id Identifier) (Image, error) {
  406. row := s.db.QueryRow("SELECT * FROM images WHERE id = ?", id)
  407. var rowNum int
  408. var title, desc, created, category string
  409. if err := row.Scan(&rowNum, &id, &title, &desc, &created, &category); err != nil {
  410. if errors.Is(err, sql.ErrNoRows) {
  411. return Image{}, ErrNotExists
  412. }
  413. return Image{}, err
  414. }
  415. data, err := s.imageIO.Get(id)
  416. if err != nil {
  417. return Image{}, err
  418. }
  419. return Image{Ident: id, Title: title, Desc: desc, Data: data, Created: created, Category: category}, nil
  420. }
  421. /*
  422. Get all of the images from the datastore
  423. */
  424. func (s *SQLiteRepo) GetAllImages() []Image {
  425. rows, err := s.db.Query("SELECT * FROM images")
  426. if err != nil {
  427. log.Fatal(err)
  428. }
  429. imgs := []Image{}
  430. for rows.Next() {
  431. var img Image
  432. var rowNum int
  433. err := rows.Scan(&rowNum, &img.Ident, &img.Title, &img.Desc, &img.Created, &img.Category)
  434. if err != nil {
  435. log.Fatal(err)
  436. }
  437. b, err := s.imageIO.Get(img.Ident)
  438. if err != nil {
  439. fmt.Printf("Failed to get image: %+v\nError: %s\n", img, err.Error())
  440. continue
  441. }
  442. imgs = append(imgs, Image{Ident: img.Ident, Title: img.Title, Desc: img.Desc, Data: b, Created: img.Created, Category: img.Category})
  443. }
  444. err = rows.Err()
  445. if err != nil {
  446. log.Fatal(err)
  447. }
  448. return imgs
  449. }
  450. func (s *SQLiteRepo) GetImagesByCategory(category string) []Image {
  451. rows, err := s.db.Query("SELECT * FROM images WHERE category = ?", category)
  452. if err != nil {
  453. log.Fatal(err)
  454. }
  455. imgs := []Image{}
  456. for rows.Next() {
  457. var img Image
  458. var rowNum int
  459. err := rows.Scan(&rowNum, &img.Ident, &img.Title, &img.Desc, &img.Created, &img.Category)
  460. if err != nil {
  461. log.Fatal(err)
  462. }
  463. b, err := s.imageIO.Get(img.Ident)
  464. if err != nil {
  465. fmt.Printf("Failed to get image: %+v\nError: %s\n", img, err.Error())
  466. }
  467. imgs = append(imgs, Image{Ident: img.Ident, Title: img.Title, Desc: img.Desc, Data: b, Created: img.Created, Category: img.Category})
  468. }
  469. err = rows.Err()
  470. if err != nil {
  471. log.Fatal(err)
  472. }
  473. return imgs
  474. }
  475. /*
  476. Add an image to the database
  477. :param title: the title of the image
  478. :param location: the location to save the image to
  479. :param desc: the description of the image, if any
  480. :param data: the binary data for the image
  481. */
  482. func (s *SQLiteRepo) AddImage(data []byte, title string, desc string, category string) (Identifier, error) {
  483. id := newIdentifier()
  484. err := s.imageIO.Put(data, id)
  485. if err != nil {
  486. return Identifier(""), err
  487. }
  488. _, err = s.db.Exec("INSERT INTO images (id, title, desc, created, category) VALUES (?,?,?,?,?)", string(id), title, desc, time.Now().String(), category)
  489. if err != nil {
  490. return Identifier(""), err
  491. }
  492. return id, nil
  493. }
  494. /*
  495. Updates a document in the database with the supplied. Only changes the title, the body, category. Keys off of the documents Identifier
  496. :param doc: the Document to upload into the database
  497. */
  498. func (s *SQLiteRepo) UpdateDocument(doc Document) error {
  499. tx, err := s.db.Begin()
  500. if err != nil {
  501. return err
  502. }
  503. stmt, err := tx.Prepare("UPDATE posts SET title = ?, body = ?, category = ?, sample = ? WHERE id = ?;")
  504. if err != nil {
  505. tx.Rollback()
  506. return err
  507. }
  508. res, err := stmt.Exec(doc.Title, doc.Body, doc.Category, doc.MakeSample(), doc.Ident)
  509. if err != nil {
  510. tx.Rollback()
  511. return err
  512. }
  513. affected, _ := res.RowsAffected()
  514. if affected != 1 {
  515. return ErrNotExists
  516. }
  517. tx.Commit()
  518. return nil
  519. }
  520. /*
  521. Adds a LinkPair to the menu database table
  522. :param item: the LinkPair to upload
  523. */
  524. func (s *SQLiteRepo) AddMenuItem(item LinkPair) error {
  525. tx, err := s.db.Begin()
  526. if err != nil {
  527. return err
  528. }
  529. fmt.Printf("from AddMenuItem: %+v\n", item)
  530. foundItem, found := s.GetMenuItemByName(item.Link, item.Text)
  531. if found {
  532. fmt.Printf("from error in AddMenuItem: %+v\n", foundItem)
  533. tx.Rollback()
  534. return ErrDuplicate
  535. }
  536. stmt, _ := tx.Prepare("INSERT INTO menu(link, text) VALUES (?,?)")
  537. _, err = stmt.Exec(item.Link, item.Text)
  538. if err != nil {
  539. tx.Rollback()
  540. return err
  541. }
  542. tx.Commit()
  543. return nil
  544. }
  545. /*
  546. Adds an item to the navbar database table
  547. :param item: the NavBarItem to upload
  548. */
  549. func (s *SQLiteRepo) AddNavbarItem(item NavBarItem) error {
  550. tx, err := s.db.Begin()
  551. if err != nil {
  552. return err
  553. }
  554. _, found := s.GetNavbarLink(item.Link, item.Redirect)
  555. if found {
  556. tx.Rollback()
  557. return ErrDuplicate
  558. }
  559. stmt, err := tx.Prepare("INSERT INTO navbar(png, link, redirect) VALUES (?,?,?)")
  560. if err != nil {
  561. tx.Rollback()
  562. return err
  563. }
  564. _, err = stmt.Exec(item.Png, item.Link, item.Redirect)
  565. if err != nil {
  566. tx.Rollback()
  567. return err
  568. }
  569. tx.Commit()
  570. return nil
  571. }
  572. /*
  573. Adds an asset to the asset database table asset
  574. :param name: the name of the asset (filename)
  575. :param data: the byte array of the PNG to upload TODO: limit this to 256kb
  576. */
  577. func (s *SQLiteRepo) AddAsset(name string, data []byte) error {
  578. tx, err := s.db.Begin()
  579. if err != nil {
  580. return err
  581. }
  582. _, found := s.GetAsset(name)
  583. if found {
  584. tx.Rollback()
  585. return ErrDuplicate
  586. }
  587. stmt, _ := tx.Prepare("INSERT INTO assets(name, data) VALUES (?,?)")
  588. _, err = stmt.Exec(name, data)
  589. if err != nil {
  590. tx.Rollback()
  591. return err
  592. }
  593. tx.Commit()
  594. return nil
  595. }
  596. /*
  597. Adds a document to the database (for text posts)
  598. :param doc: the Document to add
  599. */
  600. func (s *SQLiteRepo) AddDocument(doc Document) (Identifier, error) {
  601. id := newIdentifier()
  602. tx, err := s.db.Begin()
  603. if err != nil {
  604. return Identifier(""), err
  605. }
  606. stmt, _ := tx.Prepare("INSERT INTO posts(id, title, created, body, category, sample) VALUES (?,?,?,?,?,?)")
  607. _, err = stmt.Exec(id, doc.Title, doc.Created, doc.Body, doc.Category, doc.MakeSample())
  608. if err != nil {
  609. tx.Rollback()
  610. return Identifier(""), err
  611. }
  612. tx.Commit()
  613. return id, nil
  614. }
  615. /*
  616. Add an entry to the 'admin' table in the database
  617. :param item: an admin table k/v text to redirect pair
  618. :param tableName: the name of the table to populate the link in on the UI
  619. */
  620. func (s *SQLiteRepo) AddAdminTableEntry(item TableData, category string) error {
  621. tx, err := s.db.Begin()
  622. if err != nil {
  623. return err
  624. }
  625. _, found := s.GetAdminTableEntry(item.DisplayName, item.Link, category)
  626. if found {
  627. tx.Rollback()
  628. return ErrDuplicate
  629. }
  630. stmt, _ := tx.Prepare("INSERT INTO admin (display_name, link, category) VALUES (?,?,?)")
  631. _, err = stmt.Exec(item.DisplayName, item.Link, category)
  632. if err != nil {
  633. tx.Rollback()
  634. return err
  635. }
  636. tx.Commit()
  637. return nil
  638. }
  639. /*
  640. Delete a document from the db
  641. :param id: the identifier of the document to remove
  642. */
  643. func (s *SQLiteRepo) DeleteDocument(id Identifier) error {
  644. tx, err := s.db.Begin()
  645. if err != nil {
  646. return err
  647. }
  648. stmt, _ := tx.Prepare("DELETE FROM posts WHERE id=?")
  649. _, err = stmt.Exec(id)
  650. if err != nil {
  651. tx.Rollback()
  652. return err
  653. }
  654. tx.Commit()
  655. return nil
  656. }
  657. /*
  658. Delete navigation bar item
  659. :param id: the name or 'id' of the navbar item to remove
  660. */
  661. func (s *SQLiteRepo) DeleteNavbarItem(id Identifier) error {
  662. tx, err := s.db.Begin()
  663. if err != nil {
  664. return err
  665. }
  666. stmt, _ := tx.Prepare("DELETE FROM navbar WHERE link=?")
  667. result, err := stmt.Exec(id)
  668. if err != nil {
  669. tx.Rollback()
  670. return err
  671. }
  672. rowsAffected, _ := result.RowsAffected()
  673. if rowsAffected < 1 {
  674. return ErrNotExists
  675. }
  676. tx.Commit()
  677. return nil
  678. }
  679. // Get all Hosts from the host table
  680. func (s *SQLiteRepo) AllDocuments() []Document {
  681. rows, err := s.db.Query("SELECT * FROM posts")
  682. if err != nil {
  683. fmt.Printf("There was an issue getting all posts. %s", err.Error())
  684. return nil
  685. }
  686. defer rows.Close()
  687. all := []Document{}
  688. for rows.Next() {
  689. var post Document
  690. if err := rows.Scan(&post.Row, &post.Ident, &post.Title, &post.Created, &post.Body, &post.Category, &post.Sample); err != nil {
  691. fmt.Printf("There was an error getting all documents. %s", err.Error())
  692. return nil
  693. }
  694. all = append(all, post)
  695. }
  696. return all
  697. }
  698. type InvalidSkipArg struct{ Skip int }
  699. func (i *InvalidSkipArg) Error() string {
  700. return fmt.Sprintf("Invalid skip amount was passed: %v", i.Skip)
  701. }
  702. type ImageStoreItem struct {
  703. Identifier string `json:"identifier"`
  704. Filename string `json:"filename"`
  705. AbsolutePath string `json:"absolute_path"`
  706. Title string `json:"title" form:"title"`
  707. Created string `json:"created"`
  708. Desc string `json:"description" form:"description"`
  709. Category string `json:"category"`
  710. ApiPath string
  711. }
  712. /*
  713. Function to return the location of the image store. Wrapping the env call in
  714. a function so that refactoring is easier
  715. */
  716. func GetImageStore() string {
  717. return os.Getenv(env.IMAGE_STORE)
  718. }
  719. // Wrapping the new id call in a function to make refactoring easier
  720. func newIdentifier() Identifier {
  721. return Identifier(uuid.NewString())
  722. }