github.com/readium/readium-lcp-server@v0.0.0-20240101192032-6e95190e99f1/license_statuses/license_statuses.go (about)

     1  // Copyright 2020 Readium Foundation. All rights reserved.
     2  // Use of this source code is governed by a BSD-style license
     3  // that can be found in the LICENSE file exposed on Github (readium) in the project repository.
     4  
     5  package licensestatuses
     6  
     7  import (
     8  	"database/sql"
     9  	"errors"
    10  	"log"
    11  	"time"
    12  
    13  	"github.com/readium/readium-lcp-server/config"
    14  	"github.com/readium/readium-lcp-server/status"
    15  )
    16  
    17  // ErrNotFound is license status not found
    18  var ErrNotFound = errors.New("license Status not found")
    19  
    20  // LicenseStatuses is an interface
    21  type LicenseStatuses interface {
    22  	GetByID(id int) (*LicenseStatus, error)
    23  	Add(ls LicenseStatus) error
    24  	List(deviceLimit int64, limit int64, offset int64) func() (LicenseStatus, error)
    25  	GetByLicenseID(id string) (*LicenseStatus, error)
    26  	Update(ls LicenseStatus) error
    27  }
    28  
    29  type dbLicenseStatuses struct {
    30  	db               *sql.DB
    31  	dbGet            *sql.Stmt
    32  	dbList           *sql.Stmt
    33  	dbGetByLicenseID *sql.Stmt
    34  }
    35  
    36  // Get retrieves a license status by id
    37  func (i dbLicenseStatuses) GetByID(id int) (*LicenseStatus, error) {
    38  	var statusDB int64
    39  	ls := LicenseStatus{}
    40  
    41  	var potentialRightsEnd *time.Time
    42  	var licenseUpdate *time.Time
    43  	var statusUpdate *time.Time
    44  
    45  	row := i.dbGet.QueryRow(id)
    46  	err := row.Scan(&ls.ID, &statusDB, &licenseUpdate, &statusUpdate, &ls.DeviceCount, &potentialRightsEnd, &ls.LicenseRef, &ls.CurrentEndLicense)
    47  
    48  	if err == nil {
    49  		status.GetStatus(statusDB, &ls.Status)
    50  
    51  		ls.Updated = new(Updated)
    52  
    53  		if (potentialRightsEnd != nil) && (!(*potentialRightsEnd).IsZero()) {
    54  			ls.PotentialRights = new(PotentialRights)
    55  			ls.PotentialRights.End = potentialRightsEnd
    56  		}
    57  
    58  		ls.Updated.Status = statusUpdate
    59  		ls.Updated.License = licenseUpdate
    60  		// fix an issue with clients which test that the date of last update of the license
    61  		// is after the date of creation of the X509 certificate.
    62  		// Associated with a fix to the license server.
    63  		if config.Config.LcpServer.CertDate != "" {
    64  			certDate, err := time.Parse("2006-01-02", config.Config.LcpServer.CertDate)
    65  			if err == nil {
    66  				if ls.Updated.License == nil || ls.Updated.License.Before(certDate) {
    67  					ls.Updated.License = &certDate
    68  				}
    69  			}
    70  		}
    71  	} else {
    72  		if err == sql.ErrNoRows {
    73  			return nil, ErrNotFound
    74  		}
    75  	}
    76  
    77  	return &ls, err
    78  }
    79  
    80  // Add adds license status to database
    81  func (i dbLicenseStatuses) Add(ls LicenseStatus) error {
    82  
    83  	statusDB, err := status.SetStatus(ls.Status)
    84  	if err == nil {
    85  		var end *time.Time
    86  		end = nil
    87  		if ls.PotentialRights != nil && ls.PotentialRights.End != nil && !(*ls.PotentialRights.End).IsZero() {
    88  			end = ls.PotentialRights.End
    89  		}
    90  		_, err = i.db.Exec(`INSERT INTO license_status 
    91  		(status, license_updated, status_updated, device_count, potential_rights_end, license_ref,  rights_end)
    92  		 VALUES (?, ?, ?, ?, ?, ?, ?)`,
    93  			statusDB, ls.Updated.License, ls.Updated.Status, ls.DeviceCount, end, ls.LicenseRef, ls.CurrentEndLicense)
    94  	}
    95  
    96  	return err
    97  }
    98  
    99  // List gets license statuses which have devices count more than devices limit
   100  // input parameters: limit - how many license statuses need to get, offset - from what position need to start
   101  func (i dbLicenseStatuses) List(deviceLimit int64, limit int64, offset int64) func() (LicenseStatus, error) {
   102  
   103  	var rows *sql.Rows
   104  	var err error
   105  	driver, _ := config.GetDatabase(config.Config.LsdServer.Database)
   106  	if driver == "mssql" {
   107  		rows, err = i.dbList.Query(deviceLimit, offset, limit)
   108  	} else {
   109  		rows, err = i.dbList.Query(deviceLimit, limit, offset)
   110  	}
   111  	if err != nil {
   112  		return func() (LicenseStatus, error) { return LicenseStatus{}, err }
   113  	}
   114  
   115  	return func() (LicenseStatus, error) {
   116  		var statusDB int64
   117  		var err error
   118  
   119  		ls := LicenseStatus{}
   120  		ls.Updated = new(Updated)
   121  		if rows.Next() {
   122  			err = rows.Scan(&ls.ID, &statusDB, &ls.Updated.License, &ls.Updated.Status, &ls.DeviceCount, &ls.LicenseRef)
   123  
   124  			if err == nil {
   125  				status.GetStatus(statusDB, &ls.Status)
   126  			}
   127  		} else {
   128  			rows.Close()
   129  			err = ErrNotFound
   130  		}
   131  		return ls, err
   132  	}
   133  }
   134  
   135  // GetByLicenseID gets license status by license id (uuid)
   136  func (i dbLicenseStatuses) GetByLicenseID(licenseID string) (*LicenseStatus, error) {
   137  	var statusDB int64
   138  	ls := LicenseStatus{}
   139  
   140  	var potentialRightsEnd *time.Time
   141  	var licenseUpdate *time.Time
   142  	var statusUpdate *time.Time
   143  
   144  	row := i.dbGetByLicenseID.QueryRow(licenseID)
   145  	err := row.Scan(&ls.ID, &statusDB, &licenseUpdate, &statusUpdate, &ls.DeviceCount, &potentialRightsEnd, &ls.LicenseRef, &ls.CurrentEndLicense)
   146  
   147  	if err == nil {
   148  		status.GetStatus(statusDB, &ls.Status)
   149  
   150  		ls.Updated = new(Updated)
   151  
   152  		if (potentialRightsEnd != nil) && (!(*potentialRightsEnd).IsZero()) {
   153  			ls.PotentialRights = new(PotentialRights)
   154  			ls.PotentialRights.End = potentialRightsEnd
   155  		}
   156  
   157  		ls.Updated.Status = statusUpdate
   158  		ls.Updated.License = licenseUpdate
   159  		// fix an issue with clients which test that the date of last update of the license
   160  		// is after the date of creation of the X509 certificate.
   161  		// Associated with a fix to the license server.
   162  		if config.Config.LcpServer.CertDate != "" {
   163  			certDate, err := time.Parse("2006-01-02", config.Config.LcpServer.CertDate)
   164  			if err == nil {
   165  				if ls.Updated.License == nil || ls.Updated.License.Before(certDate) {
   166  					ls.Updated.License = &certDate
   167  				}
   168  			}
   169  		}
   170  	} else {
   171  		if err == sql.ErrNoRows {
   172  			return nil, ErrNotFound
   173  		}
   174  	}
   175  
   176  	return &ls, err
   177  }
   178  
   179  // Update updates a license status
   180  func (i dbLicenseStatuses) Update(ls LicenseStatus) error {
   181  
   182  	statusInt, err := status.SetStatus(ls.Status)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	var potentialRightsEnd *time.Time
   188  
   189  	if ls.PotentialRights != nil && ls.PotentialRights.End != nil && !(*ls.PotentialRights.End).IsZero() {
   190  		potentialRightsEnd = ls.PotentialRights.End
   191  	}
   192  
   193  	var result sql.Result
   194  	result, err = i.db.Exec(`UPDATE license_status SET status=?, license_updated=?, status_updated=?, 
   195  	device_count=?,potential_rights_end=?, rights_end=?  WHERE id=?`,
   196  		statusInt, ls.Updated.License, ls.Updated.Status, ls.DeviceCount, potentialRightsEnd, ls.CurrentEndLicense, ls.ID)
   197  
   198  	if err == nil {
   199  		if r, _ := result.RowsAffected(); r == 0 {
   200  			return ErrNotFound
   201  		}
   202  	}
   203  	return err
   204  }
   205  
   206  // Open defines scripts for queries & create table license_status if it does not exist
   207  func Open(db *sql.DB) (l LicenseStatuses, err error) {
   208  
   209  	driver, _ := config.GetDatabase(config.Config.LsdServer.Database)
   210  
   211  	// if sqlite, create the license table if it does not exist
   212  	if driver == "sqlite3" {
   213  		_, err = db.Exec(tableDef)
   214  		if err != nil {
   215  			log.Println("Error creating license_status table")
   216  			return
   217  		}
   218  	}
   219  
   220  	dbGet, err := db.Prepare("SELECT * FROM license_status WHERE id = ?")
   221  	if err != nil {
   222  		return
   223  	}
   224  
   225  	var dbList *sql.Stmt
   226  	if driver == "mssql" {
   227  		dbList, err = db.Prepare(`SELECT id, status, license_updated, status_updated, device_count, license_ref FROM license_status WHERE device_count >= ?
   228  		ORDER BY id DESC OFFSET ? ROWS FETCH NEXT ? ROWS ONLY`)
   229  	} else {
   230  		dbList, err = db.Prepare(`SELECT id, status, license_updated, status_updated, device_count, license_ref FROM license_status WHERE device_count >= ?
   231  		ORDER BY id DESC LIMIT ? OFFSET ?`)
   232  
   233  	}
   234  	if err != nil {
   235  		return
   236  	}
   237  
   238  	dbGetByLicenseID, err := db.Prepare("SELECT * FROM license_status where license_ref = ?")
   239  	if err != nil {
   240  		return
   241  	}
   242  
   243  	l = dbLicenseStatuses{db, dbGet, dbList, dbGetByLicenseID}
   244  	return
   245  }
   246  
   247  const tableDef = "CREATE TABLE IF NOT EXISTS license_status (" +
   248  	"id INTEGER PRIMARY KEY," +
   249  	"status int(11) NOT NULL," +
   250  	"license_updated datetime NOT NULL," +
   251  	"status_updated datetime NOT NULL," +
   252  	"device_count int(11) DEFAULT NULL," +
   253  	"potential_rights_end datetime DEFAULT NULL," +
   254  	"license_ref varchar(255) NOT NULL," +
   255  	"rights_end datetime DEFAULT NULL  " +
   256  	");" +
   257  	"CREATE INDEX IF NOT EXISTS license_ref_index on license_status (license_ref);"