/* * Copyright (c) 2024 Your Name / Yggmail Contributor * (Original Copyright (c) 2021 Neil Alexander) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package sqlite3 import ( "database/sql" "fmt" ) type TableMailboxes struct { db *sql.DB writer *Writer selectMailboxes *sql.Stmt listMailboxes *sql.Stmt listMailboxesSubscribed *sql.Stmt createMailbox *sql.Stmt renameMailbox *sql.Stmt deleteMailbox *sql.Stmt subscribeMailbox *sql.Stmt } // Мы изменили схему: PRIMARY KEY теперь составной (аккаунт + папка) const mailboxesSchema = ` CREATE TABLE IF NOT EXISTS mailboxes ( account_pubkey TEXT NOT NULL, mailbox TEXT NOT NULL DEFAULT('INBOX'), subscribed BOOLEAN NOT NULL DEFAULT 1, PRIMARY KEY(account_pubkey, mailbox), FOREIGN KEY(account_pubkey) REFERENCES accounts(pubkey) ON DELETE CASCADE ); ` const mailboxesList = ` SELECT mailbox FROM mailboxes WHERE account_pubkey = $1 ` const mailboxesListSubscribed = ` SELECT mailbox FROM mailboxes WHERE account_pubkey = $1 AND subscribed = 1 ` const mailboxesSelect = ` SELECT mailbox FROM mailboxes WHERE account_pubkey = $1 AND mailbox = $2 ` const mailboxesCreate = ` INSERT OR IGNORE INTO mailboxes (account_pubkey, mailbox) VALUES($1, $2) ` const mailboxesRename = ` UPDATE mailboxes SET mailbox = $2 WHERE account_pubkey = $1 AND mailbox = $3 ` const mailboxesDelete = ` DELETE FROM mailboxes WHERE account_pubkey = $1 AND mailbox = $2 ` const mailboxesSubscribe = ` UPDATE mailboxes SET subscribed = $2 WHERE account_pubkey = $1 AND mailbox = $3 ` func NewTableMailboxes(db *sql.DB, writer *Writer) (*TableMailboxes, error) { t := &TableMailboxes{ db: db, writer: writer, } _, err := db.Exec(mailboxesSchema) if err != nil { return nil, fmt.Errorf("db.Exec: %w", err) } t.listMailboxes, err = db.Prepare(mailboxesList) if err != nil { return nil, fmt.Errorf("db.Prepare(mailboxesList): %w", err) } t.listMailboxesSubscribed, err = db.Prepare(mailboxesListSubscribed) if err != nil { return nil, fmt.Errorf("db.Prepare(mailboxesListSubscribed): %w", err) } t.selectMailboxes, err = db.Prepare(mailboxesSelect) if err != nil { return nil, fmt.Errorf("db.Prepare(mailboxesSelect): %w", err) } t.createMailbox, err = db.Prepare(mailboxesCreate) if err != nil { return nil, fmt.Errorf("db.Prepare(mailboxesCreate): %w", err) } t.deleteMailbox, err = db.Prepare(mailboxesDelete) if err != nil { return nil, fmt.Errorf("db.Prepare(mailboxesDelete): %w", err) } t.renameMailbox, err = db.Prepare(mailboxesRename) if err != nil { return nil, fmt.Errorf("db.Prepare(mailboxesRename): %w", err) } t.subscribeMailbox, err = db.Prepare(mailboxesSubscribe) if err != nil { return nil, fmt.Errorf("db.Prepare(mailboxesSubscribe): %w", err) } return t, nil } // Теперь все методы принимают accountPubKey первым аргументом func (t *TableMailboxes) MailboxList(accountPubKey string, onlySubscribed bool) ([]string, error) { stmt := t.listMailboxes if onlySubscribed { stmt = t.listMailboxesSubscribed } rows, err := stmt.Query(accountPubKey) if err != nil { return nil, fmt.Errorf("t.listMailboxes.Query: %w", err) } defer rows.Close() var mailboxes []string for rows.Next() { var mailbox string if err := rows.Scan(&mailbox); err != nil { return nil, fmt.Errorf("rows.Scan: %w", err) } mailboxes = append(mailboxes, mailbox) } return mailboxes, nil } func (t *TableMailboxes) MailboxSelect(accountPubKey string, mailbox string) (bool, error) { row := t.selectMailboxes.QueryRow(accountPubKey, mailbox) var got string err := row.Scan(&got) if err != nil { if err == sql.ErrNoRows { return false, nil } return false, fmt.Errorf("row.Scan: %w", err) } return mailbox == got, nil } func (t *TableMailboxes) MailboxCreate(accountPubKey string, name string) error { return t.writer.Do(t.db, nil, func(txn *sql.Tx) error { _, err := t.createMailbox.Exec(accountPubKey, name) return err }) } func (t *TableMailboxes) MailboxRename(accountPubKey string, old, new string) error { return t.writer.Do(t.db, nil, func(txn *sql.Tx) error { _, err := t.renameMailbox.Exec(accountPubKey, new, old) return err }) } func (t *TableMailboxes) MailboxDelete(accountPubKey string, name string) error { return t.writer.Do(t.db, nil, func(txn *sql.Tx) error { _, err := t.deleteMailbox.Exec(accountPubKey, name) return err }) } func (t *TableMailboxes) MailboxSubscribe(accountPubKey string, name string, subscribed bool) error { sn := 1 if !subscribed { sn = 0 } return t.writer.Do(t.db, nil, func(txn *sql.Tx) error { _, err := t.subscribeMailbox.Exec(accountPubKey, sn, name) return err }) }