github.com/readium/readium-lcp-server@v0.0.0-20240509124024-799e77a0bbd6/license/store.go (about)

     1  // Copyright 2017 European Digital Reading Lab. All rights reserved.
     2  // Licensed to the Readium Foundation under one or more contributor license agreements.
     3  // Use of this source code is governed by a BSD-style license
     4  // that can be found in the LICENSE file exposed on Github (readium) in the project repository.
     5  
     6  package license
     7  
     8  import (
     9  	"database/sql"
    10  	"errors"
    11  	"log"
    12  	"time"
    13  
    14  	"github.com/readium/readium-lcp-server/config"
    15  	"github.com/readium/readium-lcp-server/dbutils"
    16  )
    17  
    18  var ErrNotFound = errors.New("License not found")
    19  
    20  type Store interface {
    21  	ListAll(page int, pageNum int) func() (LicenseReport, error)
    22  	ListByContentID(ContentID string, page int, pageNum int) func() (LicenseReport, error)
    23  	UpdateRights(l License) error
    24  	Update(l License) error
    25  	UpdateLsdStatus(id string, status int32) error
    26  	Add(l License) error
    27  	Get(id string) (License, error)
    28  }
    29  
    30  type sqlStore struct {
    31  	db                *sql.DB
    32  	dbGetByID         *sql.Stmt
    33  	dbList            *sql.Stmt
    34  	dbListByContentID *sql.Stmt
    35  }
    36  
    37  // ListAll lists all licenses in ante-chronological order
    38  // pageNum starts at 0
    39  func (s *sqlStore) ListAll(pageSize int, pageNum int) func() (LicenseReport, error) {
    40  
    41  	var rows *sql.Rows
    42  	var err error
    43  	driver, _ := config.GetDatabase(config.Config.LcpServer.Database)
    44  	if driver == "mssql" {
    45  		rows, err = s.dbList.Query(pageNum*pageSize, pageSize)
    46  	} else {
    47  		rows, err = s.dbList.Query(pageSize, pageNum*pageSize)
    48  	}
    49  	if err != nil {
    50  		return func() (LicenseReport, error) { return LicenseReport{}, err }
    51  	}
    52  	return func() (LicenseReport, error) {
    53  		var l LicenseReport
    54  		var err error
    55  		l.User = UserInfo{}
    56  		l.Rights = new(UserRights)
    57  		if rows.Next() {
    58  			err = rows.Scan(&l.ID, &l.User.ID, &l.Provider, &l.Issued, &l.Updated,
    59  				&l.Rights.Print, &l.Rights.Copy, &l.Rights.Start, &l.Rights.End, &l.ContentID)
    60  		} else {
    61  			rows.Close()
    62  			err = ErrNotFound
    63  		}
    64  		return l, err
    65  	}
    66  }
    67  
    68  // ListByContentID lists licenses for a given ContentID
    69  // pageNum starting at 0
    70  func (s *sqlStore) ListByContentID(contentID string, pageSize int, pageNum int) func() (LicenseReport, error) {
    71  
    72  	var rows *sql.Rows
    73  	var err error
    74  	driver, _ := config.GetDatabase(config.Config.LcpServer.Database)
    75  	if driver == "mssql" {
    76  		rows, err = s.dbListByContentID.Query(contentID, pageNum*pageSize, pageSize)
    77  	} else {
    78  		rows, err = s.dbListByContentID.Query(contentID, pageSize, pageNum*pageSize)
    79  	}
    80  	if err != nil {
    81  		return func() (LicenseReport, error) { return LicenseReport{}, err }
    82  	}
    83  	return func() (LicenseReport, error) {
    84  		var l LicenseReport
    85  		var err error
    86  		l.User = UserInfo{}
    87  		l.Rights = new(UserRights)
    88  		if rows.Next() {
    89  			err = rows.Scan(&l.ID, &l.User.ID, &l.Provider, &l.Issued, &l.Updated,
    90  				&l.Rights.Print, &l.Rights.Copy, &l.Rights.Start, &l.Rights.End, &l.ContentID)
    91  		} else {
    92  			rows.Close()
    93  			err = ErrNotFound
    94  		}
    95  		return l, err
    96  	}
    97  }
    98  
    99  // UpdateRights
   100  func (s *sqlStore) UpdateRights(l License) error {
   101  
   102  	result, err := s.db.Exec(dbutils.GetParamQuery(config.Config.LcpServer.Database, "UPDATE license SET rights_print=?, rights_copy=?, rights_start=?, rights_end=?, updated=? WHERE id=?"),
   103  		l.Rights.Print, l.Rights.Copy, l.Rights.Start, l.Rights.End, time.Now().UTC().Truncate(time.Second), l.ID)
   104  
   105  	if err == nil {
   106  		if r, _ := result.RowsAffected(); r == 0 {
   107  			return ErrNotFound
   108  		}
   109  	}
   110  	return err
   111  }
   112  
   113  // Add creates a new record in the license table
   114  func (s *sqlStore) Add(l License) error {
   115  
   116  	_, err := s.db.Exec(dbutils.GetParamQuery(config.Config.LcpServer.Database, `INSERT INTO license (id, user_id, provider, issued, updated,
   117  	rights_print, rights_copy, rights_start, rights_end, content_fk) 
   118  	VALUES (?, ?, ?, ?, ?, ?, ?, ?,  ?, ?)`),
   119  		l.ID, l.User.ID, l.Provider, l.Issued, nil,
   120  		l.Rights.Print, l.Rights.Copy, l.Rights.Start, l.Rights.End,
   121  		l.ContentID)
   122  	return err
   123  }
   124  
   125  // Update updates a record in the license table
   126  func (s *sqlStore) Update(l License) error {
   127  
   128  	_, err := s.db.Exec(dbutils.GetParamQuery(config.Config.LcpServer.Database, `UPDATE license SET user_id=?,provider=?,updated=?,
   129  				rights_print=?,	rights_copy=?,	rights_start=?,	rights_end=?, content_fk =?
   130  				WHERE id=?`),
   131  		l.User.ID, l.Provider,
   132  		time.Now().UTC().Truncate(time.Second),
   133  		l.Rights.Print, l.Rights.Copy, l.Rights.Start, l.Rights.End,
   134  		l.ContentID,
   135  		l.ID)
   136  
   137  	return err
   138  }
   139  
   140  // UpdateLsdStatus
   141  func (s *sqlStore) UpdateLsdStatus(id string, status int32) error {
   142  
   143  	_, err := s.db.Exec(dbutils.GetParamQuery(config.Config.LcpServer.Database, `UPDATE license SET lsd_status =? WHERE id=?`),
   144  		status, id)
   145  
   146  	return err
   147  }
   148  
   149  // Get a license from the db
   150  func (s *sqlStore) Get(id string) (License, error) {
   151  
   152  	row := s.dbGetByID.QueryRow(id)
   153  	var l License
   154  	l.Rights = new(UserRights)
   155  	err := row.Scan(&l.ID, &l.User.ID, &l.Provider, &l.Issued, &l.Updated,
   156  		&l.Rights.Print, &l.Rights.Copy, &l.Rights.Start, &l.Rights.End, &l.ContentID)
   157  	if err == sql.ErrNoRows {
   158  		err = ErrNotFound
   159  	}
   160  	return l, err
   161  }
   162  
   163  // Open
   164  func Open(db *sql.DB) (store Store, err error) {
   165  
   166  	driver, _ := config.GetDatabase(config.Config.LcpServer.Database)
   167  
   168  	// if sqlite, create the license table if it does not exist
   169  	if driver == "sqlite3" {
   170  		_, err := db.Exec(tableDef)
   171  		if err != nil {
   172  			log.Println("Error creating sqlite license table")
   173  			return nil, err
   174  		}
   175  	}
   176  
   177  	var dbList *sql.Stmt
   178  	if driver == "mssql" {
   179  		dbList, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, rights_print, rights_copy, rights_start, rights_end, content_fk
   180  	FROM license ORDER BY issued desc OFFSET ? ROWS FETCH NEXT ? ROWS ONLY`))
   181  	} else {
   182  		dbList, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, rights_print, rights_copy, rights_start, rights_end, content_fk
   183  	FROM license ORDER BY issued desc LIMIT ? OFFSET ?`))
   184  	}
   185  	if err != nil {
   186  		log.Println("Error preparing dbList")
   187  		return
   188  	}
   189  
   190  	var dbListByContentID *sql.Stmt
   191  	if driver == "mssql" {
   192  		dbListByContentID, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, 
   193  		rights_print, rights_copy, rights_start, rights_end, content_fk
   194  		FROM license WHERE content_fk = ? ORDER BY issued desc OFFSET ? ROWS FETCH NEXT ? ROWS ONLY`))
   195  	} else {
   196  		dbListByContentID, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, 
   197  		rights_print, rights_copy, rights_start, rights_end, content_fk
   198  		FROM license WHERE content_fk = ?  ORDER BY issued desc LIMIT ? OFFSET ?`))
   199  
   200  	}
   201  	if err != nil {
   202  		log.Println("Error preparing dbListByContentID")
   203  		return
   204  	}
   205  
   206  	var dbGetByID *sql.Stmt
   207  	dbGetByID, err = db.Prepare(dbutils.GetParamQuery(config.Config.LcpServer.Database, `SELECT id, user_id, provider, issued, updated, rights_print, rights_copy,
   208  	rights_start, rights_end, content_fk 
   209  	FROM license WHERE id = ?`))
   210  	if err != nil {
   211  		log.Println("Error preparing dbGetByID")
   212  		return
   213  	}
   214  
   215  	store = &sqlStore{db, dbGetByID, dbList, dbListByContentID}
   216  	return
   217  }
   218  
   219  const tableDef = "CREATE TABLE IF NOT EXISTS license (" +
   220  	"id varchar(255) PRIMARY KEY," +
   221  	"user_id varchar(255) NOT NULL," +
   222  	"provider varchar(255) NOT NULL," +
   223  	"issued datetime NOT NULL," +
   224  	"updated datetime DEFAULT NULL," +
   225  	"rights_print int(11) DEFAULT NULL," +
   226  	"rights_copy int(11) DEFAULT NULL," +
   227  	"rights_start datetime DEFAULT NULL," +
   228  	"rights_end datetime DEFAULT NULL," +
   229  	"content_fk varchar(255) NOT NULL," +
   230  	"lsd_status integer default 0," +
   231  	"FOREIGN KEY(content_fk) REFERENCES content(id))"