github.com/readium/readium-lcp-server@v0.0.0-20240509124024-799e77a0bbd6/license/store.go (about) 1 // Copyright 2017 European Digital Reading Lab. All rights reserved. 2 // Licensed to the Readium Foundation under one or more contributor license agreements. 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file exposed on Github (readium) in the project repository. 5 6 package license 7 8 import ( 9 "database/sql" 10 "errors" 11 "log" 12 "time" 13 14 "github.com/readium/readium-lcp-server/config" 15 "github.com/readium/readium-lcp-server/dbutils" 16 ) 17 18 var ErrNotFound = errors.New("License not found") 19 20 type Store interface { 21 ListAll(page int, pageNum int) func() (LicenseReport, error) 22 ListByContentID(ContentID string, page int, pageNum int) func() (LicenseReport, error) 23 UpdateRights(l License) error 24 Update(l License) error 25 UpdateLsdStatus(id string, status int32) error 26 Add(l License) error 27 Get(id string) (License, error) 28 } 29 30 type sqlStore struct { 31 db *sql.DB 32 dbGetByID *sql.Stmt 33 dbList *sql.Stmt 34 dbListByContentID *sql.Stmt 35 } 36 37 // ListAll lists all licenses in ante-chronological order 38 // pageNum starts at 0 39 func (s *sqlStore) ListAll(pageSize int, pageNum int) func() (LicenseReport, error) { 40 41 var rows *sql.Rows 42 var err error 43 driver, _ := config.GetDatabase(config.Config.LcpServer.Database) 44 if driver == "mssql" { 45 rows, err = s.dbList.Query(pageNum*pageSize, pageSize) 46 } else { 47 rows, err = s.dbList.Query(pageSize, pageNum*pageSize) 48 } 49 if err != nil { 50 return func() (LicenseReport, error) { return LicenseReport{}, err } 51 } 52 return func() (LicenseReport, error) { 53 var l LicenseReport 54 var err error 55 l.User = UserInfo{} 56 l.Rights = new(UserRights) 57 if rows.Next() { 58 err = rows.Scan(&l.ID, &l.User.ID, &l.Provider, &l.Issued, &l.Updated, 59 &l.Rights.Print, &l.Rights.Copy, &l.Rights.Start, &l.Rights.End, &l.ContentID) 60 } else { 61 rows.Close() 62 err = ErrNotFound 63 } 64 return l, err 65 } 66 } 67 68 // ListByContentID lists licenses for a given ContentID 69 // pageNum starting at 0 70 func (s *sqlStore) ListByContentID(contentID string, pageSize int, pageNum int) func() (LicenseReport, error) { 71 72 var rows *sql.Rows 73 var err error 74 driver, _ := config.GetDatabase(config.Config.LcpServer.Database) 75 if driver == "mssql" { 76 rows, err = s.dbListByContentID.Query(contentID, pageNum*pageSize, pageSize) 77 } else { 78 rows, err = s.dbListByContentID.Query(contentID, pageSize, pageNum*pageSize) 79 } 80 if err != nil { 81 return func() (LicenseReport, error) { return LicenseReport{}, err } 82 } 83 return func() (LicenseReport, error) { 84 var l LicenseReport 85 var err error 86 l.User = UserInfo{} 87 l.Rights = new(UserRights) 88 if rows.Next() { 89 err = rows.Scan(&l.ID, &l.User.ID, &l.Provider, &l.Issued, &l.Updated, 90 &l.Rights.Print, &l.Rights.Copy, &l.Rights.Start, &l.Rights.End, &l.ContentID) 91 } else { 92 rows.Close() 93 err = ErrNotFound 94 } 95 return l, err 96 } 97 } 98 99 // UpdateRights 100 func (s *sqlStore) UpdateRights(l License) error { 101 102 result, err := s.db.Exec(dbutils.GetParamQuery(config.Config.LcpServer.Database, "UPDATE license SET rights_print=?, rights_copy=?, rights_start=?, rights_end=?, updated=? WHERE id=?"), 103 l.Rights.Print, l.Rights.Copy, l.Rights.Start, l.Rights.End, time.Now().UTC().Truncate(time.Second), l.ID) 104 105 if err == nil { 106 if r, _ := result.RowsAffected(); r == 0 { 107 return ErrNotFound 108 } 109 } 110 return err 111 } 112 113 // Add creates a new record in the license table 114 func (s *sqlStore) Add(l License) error { 115 116 _, err := s.db.Exec(dbutils.GetParamQuery(config.Config.LcpServer.Database, `INSERT INTO license (id, user_id, provider, issued, updated, 117 rights_print, rights_copy, rights_start, rights_end, content_fk) 118 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`), 119 l.ID, l.User.ID, l.Provider, l.Issued, nil, 120 l.Rights.Print, l.Rights.Copy, l.Rights.Start, l.Rights.End, 121 l.ContentID) 122 return err 123 } 124 125 // Update updates a record in the license table 126 func (s *sqlStore) Update(l License) error { 127 128 _, err := s.db.Exec(dbutils.GetParamQuery(config.Config.LcpServer.Database, `UPDATE license SET user_id=?,provider=?,updated=?, 129 rights_print=?, rights_copy=?, rights_start=?, rights_end=?, content_fk =? 130 WHERE id=?`), 131 l.User.ID, l.Provider, 132 time.Now().UTC().Truncate(time.Second), 133 l.Rights.Print, l.Rights.Copy, l.Rights.Start, l.Rights.End, 134 l.ContentID, 135 l.ID) 136 137 return err 138 } 139 140 // UpdateLsdStatus 141 func (s *sqlStore) UpdateLsdStatus(id string, status int32) error { 142 143 _, err := s.db.Exec(dbutils.GetParamQuery(config.Config.LcpServer.Database, `UPDATE license SET lsd_status =? WHERE id=?`), 144 status, id) 145 146 return err 147 } 148 149 // Get a license from the db 150 func (s *sqlStore) Get(id string) (License, error) { 151 152 row := s.dbGetByID.QueryRow(id) 153 var l License 154 l.Rights = new(UserRights) 155 err := row.Scan(&l.ID, &l.User.ID, &l.Provider, &l.Issued, &l.Updated, 156 &l.Rights.Print, &l.Rights.Copy, &l.Rights.Start, &l.Rights.End, &l.ContentID) 157 if err == sql.ErrNoRows { 158 err = ErrNotFound 159 } 160 return l, err 161 } 162 163 // Open 164 func Open(db *sql.DB) (store Store, err error) { 165 166 driver, _ := config.GetDatabase(config.Config.LcpServer.Database) 167 168 // if sqlite, create the license table if it does not exist 169 if driver == "sqlite3" { 170 _, err := db.Exec(tableDef) 171 if err != nil { 172 log.Println("Error creating sqlite license table") 173 return nil, err 174 } 175 } 176 177 var dbList *sql.Stmt 178 if driver == "mssql" { 179 dbList, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, rights_print, rights_copy, rights_start, rights_end, content_fk 180 FROM license ORDER BY issued desc OFFSET ? ROWS FETCH NEXT ? ROWS ONLY`)) 181 } else { 182 dbList, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, rights_print, rights_copy, rights_start, rights_end, content_fk 183 FROM license ORDER BY issued desc LIMIT ? OFFSET ?`)) 184 } 185 if err != nil { 186 log.Println("Error preparing dbList") 187 return 188 } 189 190 var dbListByContentID *sql.Stmt 191 if driver == "mssql" { 192 dbListByContentID, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, 193 rights_print, rights_copy, rights_start, rights_end, content_fk 194 FROM license WHERE content_fk = ? ORDER BY issued desc OFFSET ? ROWS FETCH NEXT ? ROWS ONLY`)) 195 } else { 196 dbListByContentID, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, 197 rights_print, rights_copy, rights_start, rights_end, content_fk 198 FROM license WHERE content_fk = ? ORDER BY issued desc LIMIT ? OFFSET ?`)) 199 200 } 201 if err != nil { 202 log.Println("Error preparing dbListByContentID") 203 return 204 } 205 206 var dbGetByID *sql.Stmt 207 dbGetByID, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, rights_print, rights_copy, 208 rights_start, rights_end, content_fk 209 FROM license WHERE id = ?`)) 210 if err != nil { 211 log.Println("Error preparing dbGetByID") 212 return 213 } 214 215 store = &sqlStore{db, dbGetByID, dbList, dbListByContentID} 216 return 217 } 218 219 const tableDef = "CREATE TABLE IF NOT EXISTS license (" + 220 "id varchar(255) PRIMARY KEY," + 221 "user_id varchar(255) NOT NULL," + 222 "provider varchar(255) NOT NULL," + 223 "issued datetime NOT NULL," + 224 "updated datetime DEFAULT NULL," + 225 "rights_print int(11) DEFAULT NULL," + 226 "rights_copy int(11) DEFAULT NULL," + 227 "rights_start datetime DEFAULT NULL," + 228 "rights_end datetime DEFAULT NULL," + 229 "content_fk varchar(255) NOT NULL," + 230 "lsd_status integer default 0," + 231 "FOREIGN KEY(content_fk) REFERENCES content(id))"