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