github.com/readium/readium-lcp-server@v0.0.0-20240509124024-799e77a0bbd6/frontend/weblicense/weblicense.go (about) 1 // Copyright (c) 2016 Readium Foundation 2 // 3 // Redistribution and use in source and binary forms, with or without modification, 4 // are permitted provided that the following conditions are met: 5 // 6 // 1. Redistributions of source code must retain the above copyright notice, this 7 // list of conditions and the following disclaimer. 8 // 2. Redistributions in binary form must reproduce the above copyright notice, 9 // this list of conditions and the following disclaimer in the documentation and/or 10 // other materials provided with the distribution. 11 // 3. Neither the name of the organization nor the names of its contributors may be 12 // used to endorse or promote products derived from this software without specific 13 // prior written permission 14 // 15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26 package weblicense 27 28 import ( 29 "database/sql" 30 "encoding/json" 31 "errors" 32 "log" 33 34 "github.com/readium/readium-lcp-server/config" 35 "github.com/readium/readium-lcp-server/dbutils" 36 ) 37 38 // License status 39 const ( 40 StatusDraft string = "draft" 41 StatusEncrypting string = "encrypting" 42 StatusError string = "error" 43 StatusOk string = "ok" 44 ) 45 46 // ErrNotFound error trown when license is not found 47 var ErrNotFound = errors.New("License not found") 48 49 // WebLicense interface for license db interaction 50 type WebLicense interface { 51 Get(id int64) (License, error) 52 GetFiltered(filter string) ([]License, error) 53 Add(license License) error 54 AddFromJSON(licensesJSON []byte) error 55 PurgeDataBase() error 56 Update(license License) error 57 Delete(id int64) error 58 } 59 60 // License struct defines a license 61 type License struct { 62 ID string `json:""` 63 PublicationTitle string `json:"publication_title"` 64 UserName string `json:"user_name"` 65 Type string `json:"type"` 66 UUID string `json:"id"` 67 DeviceCount int `json:"device_count"` 68 Status string `json:"status"` 69 PurchaseID int `json:"purchase_id"` 70 Message string `json:"message"` 71 } 72 73 // Licenses struct defines a licenses array to be transfered 74 type Licenses []struct { 75 ID string `json:""` 76 UUID string `json:"id"` 77 Status string `json:"status"` 78 DeviceCount int `json:"device_count"` 79 Message string `json:"message"` 80 } 81 82 // LicenseManager helper 83 type LicenseManager struct { 84 db *sql.DB 85 dbGetByID *sql.Stmt 86 dbGetFiltered *sql.Stmt 87 } 88 89 // Get a license for a given ID 90 func (licManager LicenseManager) Get(id int64) (License, error) { 91 92 row := licManager.dbGetByID.QueryRow(id) 93 var lic License 94 err := row.Scan( 95 &lic.ID, 96 &lic.PublicationTitle, 97 &lic.UserName, 98 &lic.Type, 99 &lic.DeviceCount, 100 &lic.Status, 101 &lic.PurchaseID, 102 &lic.Message) 103 return lic, err 104 } 105 106 // GetFiltered returns licenses with a number of registered devices higher than the parameter 107 func (licManager LicenseManager) GetFiltered(deviceLimit string) ([]License, error) { 108 109 rows, err := licManager.dbGetFiltered.Query(deviceLimit) 110 if err != nil { 111 return []License{}, err 112 } 113 defer rows.Close() 114 115 licences := make([]License, 0, 20) 116 117 for rows.Next() { 118 var lic License 119 err = rows.Scan( 120 &lic.ID, 121 &lic.PublicationTitle, 122 &lic.UserName, 123 &lic.Type, 124 &lic.DeviceCount, 125 &lic.Status, 126 &lic.PurchaseID, 127 &lic.Message) 128 if err != nil { 129 return licences, err 130 } 131 licences = append(licences, lic) 132 } 133 return licences, nil 134 } 135 136 // Add adds a new license 137 func (licManager LicenseManager) Add(licenses License) error { 138 139 _, err := licManager.db.Exec(dbutils.GetParamQuery(config.Config.FrontendServer.Database, "INSERT INTO license_view (uuid, device_count, status, message) VALUES (?, ?, ?, ?)"), 140 licenses.UUID, licenses.DeviceCount, licenses.Status, licenses.Message) 141 return err 142 } 143 144 // AddFromJSON adds a new license from a JSON string 145 func (licManager LicenseManager) AddFromJSON(licensesJSON []byte) error { 146 var licenses Licenses 147 err := json.Unmarshal(licensesJSON, &licenses) 148 if err != nil { 149 return err 150 } 151 152 add, err := licManager.db.Prepare(dbutils.GetParamQuery(config.Config.FrontendServer.Database, 153 "INSERT INTO license_view (uuid, device_count, status, message) VALUES (?, ?, ?, ?)")) 154 if err != nil { 155 return err 156 } 157 defer add.Close() 158 159 for _, l := range licenses { 160 _, err = add.Exec(l.UUID, l.DeviceCount, l.Status, l.Message) 161 if err != nil { 162 return err 163 } 164 } 165 return nil 166 } 167 168 // PurgeDataBase erases all the content of the license_view table 169 func (licManager LicenseManager) PurgeDataBase() error { 170 171 _, err := licManager.db.Exec("DELETE FROM license_view") 172 return err 173 } 174 175 // Update updates a license 176 func (licManager LicenseManager) Update(lic License) error { 177 178 _, err := licManager.db.Exec(dbutils.GetParamQuery(config.Config.FrontendServer.Database, 179 "UPDATE license_view SET device_count=?, uuid=?, status=? , message=? WHERE id = ?"), 180 lic.DeviceCount, lic.Status, lic.UUID, lic.ID, lic.Message) 181 return err 182 } 183 184 // Delete deletes a license 185 func (licManager LicenseManager) Delete(id int64) error { 186 187 _, err := licManager.db.Exec(dbutils.GetParamQuery(config.Config.FrontendServer.Database, "DELETE FROM license_view WHERE id = ?"), id) 188 return err 189 } 190 191 // Init inits the license manager 192 func Init(db *sql.DB) (i WebLicense, err error) { 193 194 driver, _ := config.GetDatabase(config.Config.FrontendServer.Database) 195 196 // if sqlite, create the content table in the frontend db if it does not exist 197 if driver == "sqlite3" { 198 _, err = db.Exec(tableDef) 199 if err != nil { 200 log.Println("Error creating license_view table") 201 return 202 } 203 } 204 205 var dbGetByID *sql.Stmt 206 dbGetByID, err = db.Prepare(dbutils.GetParamQuery(config.Config.FrontendServer.Database, 207 `SELECT l.uuid, pu.title, u.name, p.type, l.device_count, l.status, p.id, l.message 208 FROM license_view AS l 209 INNER JOIN purchase as p ON l.uuid = p.license_uuid 210 INNER JOIN publication as pu ON p.publication_id = pu.id 211 INNER JOIN "user" as u ON p.user_id = u.id 212 WHERE l.id = ?`)) 213 if err != nil { 214 log.Println("Error preparing dbGetByID") 215 return 216 } 217 218 var dbGetFiltered *sql.Stmt 219 dbGetFiltered, err = db.Prepare(dbutils.GetParamQuery(config.Config.FrontendServer.Database, 220 `SELECT l.uuid, pu.title, u.name, p.type, l.device_count, l.status, p.id, l.message FROM license_view AS l 221 INNER JOIN purchase as p ON l.uuid = p.license_uuid 222 INNER JOIN publication as pu ON p.publication_id = pu.id 223 INNER JOIN "user" as u ON p.user_id = u.id 224 WHERE l.device_count >= ?`)) 225 if err != nil { 226 log.Println("Error preparing dbGetFiltered") 227 return 228 } 229 230 i = LicenseManager{db, dbGetByID, dbGetFiltered} 231 return 232 } 233 234 const tableDef = "CREATE TABLE IF NOT EXISTS license_view (" + 235 "id integer NOT NULL PRIMARY KEY," + 236 "uuid varchar(255) NOT NULL," + 237 "device_count integer NOT NULL," + 238 "status varchar(255) NOT NULL," + 239 "message varchar(255) NOT NULL)"