github.com/readium/readium-lcp-server@v0.0.0-20240101192032-6e95190e99f1/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 ) 36 37 // License status 38 const ( 39 StatusDraft string = "draft" 40 StatusEncrypting string = "encrypting" 41 StatusError string = "error" 42 StatusOk string = "ok" 43 ) 44 45 // ErrNotFound error trown when license is not found 46 var ErrNotFound = errors.New("License not found") 47 48 // WebLicense interface for license db interaction 49 type WebLicense interface { 50 Get(id int64) (License, error) 51 GetFiltered(filter string) ([]License, error) 52 Add(license License) error 53 AddFromJSON(licensesJSON []byte) error 54 PurgeDataBase() error 55 Update(license License) error 56 Delete(id int64) error 57 } 58 59 // License struct defines a license 60 type License struct { 61 ID string `json:""` 62 PublicationTitle string `json:"publication_title"` 63 UserName string `json:"user_name"` 64 Type string `json:"type"` 65 UUID string `json:"id"` 66 DeviceCount int `json:"device_count"` 67 Status string `json:"status"` 68 PurchaseID int `json:"purchase_id"` 69 Message string `json:"message"` 70 } 71 72 // Licenses struct defines a licenses array to be transfered 73 type Licenses []struct { 74 ID string `json:""` 75 UUID string `json:"id"` 76 Status string `json:"status"` 77 DeviceCount int `json:"device_count"` 78 Message string `json:"message"` 79 } 80 81 // LicenseManager helper 82 type LicenseManager struct { 83 db *sql.DB 84 dbGetByID *sql.Stmt 85 dbGetFiltered *sql.Stmt 86 } 87 88 // Get a license for a given ID 89 func (licManager LicenseManager) Get(id int64) (License, error) { 90 91 row := licManager.dbGetByID.QueryRow(id) 92 var lic License 93 err := row.Scan( 94 &lic.ID, 95 &lic.PublicationTitle, 96 &lic.UserName, 97 &lic.Type, 98 &lic.DeviceCount, 99 &lic.Status, 100 &lic.PurchaseID, 101 &lic.Message) 102 return lic, err 103 } 104 105 // GetFiltered returns licenses with a number of registered devices higher than the parameter 106 func (licManager LicenseManager) GetFiltered(deviceLimit string) ([]License, error) { 107 108 rows, err := licManager.dbGetFiltered.Query(deviceLimit) 109 if err != nil { 110 return []License{}, err 111 } 112 defer rows.Close() 113 114 licences := make([]License, 0, 20) 115 116 for rows.Next() { 117 var lic License 118 err = rows.Scan( 119 &lic.ID, 120 &lic.PublicationTitle, 121 &lic.UserName, 122 &lic.Type, 123 &lic.DeviceCount, 124 &lic.Status, 125 &lic.PurchaseID, 126 &lic.Message) 127 if err != nil { 128 return licences, err 129 } 130 licences = append(licences, lic) 131 } 132 return licences, nil 133 } 134 135 // Add adds a new license 136 func (licManager LicenseManager) Add(licenses License) error { 137 138 _, err := licManager.db.Exec("INSERT INTO license_view (uuid, device_count, status, message) VALUES (?, ?, ?, ?)", 139 licenses.UUID, licenses.DeviceCount, licenses.Status, licenses.Message) 140 return err 141 } 142 143 // AddFromJSON adds a new license from a JSON string 144 func (licManager LicenseManager) AddFromJSON(licensesJSON []byte) error { 145 var licenses Licenses 146 err := json.Unmarshal(licensesJSON, &licenses) 147 if err != nil { 148 return err 149 } 150 151 add, err := licManager.db.Prepare("INSERT INTO license_view (uuid, device_count, status, message) VALUES (?, ?, ?, ?)") 152 if err != nil { 153 return err 154 } 155 defer add.Close() 156 157 for _, l := range licenses { 158 _, err = add.Exec(l.UUID, l.DeviceCount, l.Status, l.Message) 159 if err != nil { 160 return err 161 } 162 } 163 return nil 164 } 165 166 // PurgeDataBase erases all the content of the license_view table 167 func (licManager LicenseManager) PurgeDataBase() error { 168 169 _, err := licManager.db.Exec("DELETE FROM license_view") 170 return err 171 } 172 173 // Update updates a license 174 func (licManager LicenseManager) Update(lic License) error { 175 176 _, err := licManager.db.Exec("UPDATE license_view SET device_count=?, uuid=?, status=? , message=? WHERE id = ?", 177 lic.DeviceCount, lic.Status, lic.UUID, lic.ID, lic.Message) 178 return err 179 } 180 181 // Delete deletes a license 182 func (licManager LicenseManager) Delete(id int64) error { 183 184 _, err := licManager.db.Exec("DELETE FROM license_view WHERE id = ?", id) 185 return err 186 } 187 188 // Init inits the license manager 189 func Init(db *sql.DB) (i WebLicense, err error) { 190 191 driver, _ := config.GetDatabase(config.Config.FrontendServer.Database) 192 193 // if sqlite, create the content table in the frontend db if it does not exist 194 if driver == "sqlite3" { 195 _, err = db.Exec(tableDef) 196 if err != nil { 197 log.Println("Error creating license_view table") 198 return 199 } 200 } 201 202 var dbGetByID *sql.Stmt 203 dbGetByID, err = db.Prepare( 204 `SELECT l.uuid, pu.title, u.name, p.type, l.device_count, l.status, p.id, l.message 205 FROM license_view AS l 206 INNER JOIN purchase as p ON l.uuid = p.license_uuid 207 INNER JOIN publication as pu ON p.publication_id = pu.id 208 INNER JOIN "user" as u ON p.user_id = u.id 209 WHERE l.id = ?`) 210 if err != nil { 211 log.Println("Error preparing dbGetByID") 212 return 213 } 214 215 var dbGetFiltered *sql.Stmt 216 dbGetFiltered, err = db.Prepare( 217 `SELECT l.uuid, pu.title, u.name, p.type, l.device_count, l.status, p.id, l.message FROM license_view AS l 218 INNER JOIN purchase as p ON l.uuid = p.license_uuid 219 INNER JOIN publication as pu ON p.publication_id = pu.id 220 INNER JOIN "user" as u ON p.user_id = u.id 221 WHERE l.device_count >= ?`) 222 if err != nil { 223 log.Println("Error preparing dbGetFiltered") 224 return 225 } 226 227 i = LicenseManager{db, dbGetByID, dbGetFiltered} 228 return 229 } 230 231 const tableDef = "CREATE TABLE IF NOT EXISTS license_view (" + 232 "id integer NOT NULL PRIMARY KEY," + 233 "uuid varchar(255) NOT NULL," + 234 "device_count integer NOT NULL," + 235 "status varchar(255) NOT NULL," + 236 "message varchar(255) NOT NULL)"