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)"