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