Documentation
¶
Index ¶
- Constants
- Variables
- func Audit(ctx context.Context, store Store, action string, users []int64, targetID int64, ...)
- func BesideBytesOK(head []byte) bool
- func BesideName(filePath, ext string) string
- func ConflictName(name string, now time.Time) string
- func DelimiterName(c byte) string
- func DocExt(name string) string
- func EncodingLabel(name string) (string, bool)
- func FormatName(ext string) string
- func IsConflictName(name string) bool
- func IsPackage(b []byte) bool
- func NoticeMeta(titleKey, bodyKey string, vars srvtext.Vars) (meta map[string]any, title, body string)
- func RewriteCSV(saved []byte, d CSVDialect) []byte
- type CSVDialect
- type CSVKept
- type CSVSave
- type Declared
- type Env
- type GateError
- type Original
- type Refusal
- type Save
- type Store
- type TextDialect
- type Written
Constants ¶
const ( EncUTF8 = "utf-8" EncUTF16LE = "utf-16le" EncUTF16BE = "utf-16be" )
Encoding names.
const CSVSniffBytes = 64 << 10
CSVSniffBytes is how much of a CSV is read to learn how it is written.
const MaxSaveBytes = 256 << 20
MaxSaveBytes bounds a saved CSV: it is read whole, to be written in the file's own way. A larger one is not written.
const TextDialectHeader = "X-Filex-Text-Dialect"
TextDialectHeader is the response header an app's read of a .csv carries its dialect in (TextDialect, JSON): GET /api/files/plugins/ui/{plugin}/{view}/read.
Variables ¶
var ( // ErrNoEditor: nobody is known to have made the save. ErrNoEditor = errors.New("officesave: no editor of the save is known") // ErrNoCreate: none of the people who made it may create a file there. ErrNoCreate = errors.New("officesave: none of the editors may create a file beside the document") )
The refusals of a save Write does not write.
var BesideFormats = map[string]bool{ "docx": true, "xlsx": true, "pptx": true, "docm": true, "xlsm": true, "pptm": true, "odt": true, "ods": true, "odp": true, }
BesideFormats are the formats a save may come back in that are kept beside the file: the OOXML and ODF documents an office editor writes. The desktop app's list is held to this one (web/tests/lib/serverRuleVectors.test.ts, TestRuleVectors_BesideFormats).
var DefaultCSVDialect = CSVDialect{Comma: ',', UTF8: true}
DefaultCSVDialect is a CSV with nothing to say about itself: an empty file, or one filex could not read. Comma-separated UTF-8, no byte order mark, "\n" line ends.
var ErrDeclaration = errors.New("officesave: a csv declaration filex cannot take")
ErrDeclaration is a declaration filex cannot take: a delimiter that is not one character of `,;\t|`, an encoding it does not know, a line end other than crlf or lf.
var KeepMaxBytes int64 = 64 << 20
KeepMaxBytes bounds both the file and the save KeepCSV compares: each is held whole, with an index beside it. A larger file is written with the editor's values (RewriteCSV). A variable so that a test can lower it.
Functions ¶
func Audit ¶
func Audit(ctx context.Context, store Store, action string, users []int64, targetID int64, meta map[string]any)
Audit writes one row about a file, best-effort: a row the store refuses is logged, never a reason to undo what already happened. users are the editors, the row's user the first of them while that account is still there (the column is a reference to it).
func BesideBytesOK ¶
BesideBytesOK reports whether head - the first bytes of a save in one of BesideFormats - starts as that format does: every one of them is a zip package (OOXML, ODF). Anything else is never written beside a document, whichever editor sent it.
func BesideName ¶
BesideName is where an edit saved as ext goes: the file's own name with that extension, in its folder (`rapor.doc` → `rapor.docx`). When that name is taken the caller numbers it (`rapor (2).docx`, ops.UniqueDestNumbered).
func ConflictName ¶
ConflictName is `<stem>.filex-conflict-<UTC time>.<ext>`: what a save of a session the file moved on from is called, beside the file - the desktop app's conflict copy name too (desktop/src/openwith.ts conflictPathFor).
func DelimiterName ¶
DelimiterName is a delimiter as a person reads it: the character, `TAB` for a tab.
func EncodingLabel ¶
EncodingLabel is a declared encoding by the name filex uses for it, and whether filex knows it.
func FormatName ¶
FormatName is a type as a person reads it: "DOCX".
func IsConflictName ¶
IsConflictName reports whether name is a conflict copy's (ConflictName, numbered or not).
func IsPackage ¶
IsPackage reports whether b starts like a spreadsheet package and not like text: a zip (XLSX, ODS) or an OLE compound file (XLS). Such bytes are never written under a .csv name.
func NoticeMeta ¶
func NoticeMeta(titleKey, bodyKey string, vars srvtext.Vars) (meta map[string]any, title, body string)
NoticeMeta is a notice's words in every built-in language (`title_<lang>`, `body_<lang>`), and the row's own title and body in the instance's language (the webhook and the admin history read those).
func RewriteCSV ¶
func RewriteCSV(saved []byte, d CSVDialect) []byte
RewriteCSV turns a comma-separated UTF-8 save (what Docs 9.4 writes: a UTF-8 byte order mark, "\n" line ends) into the file's own way of writing: its delimiter, its byte order mark or none, its line ends. The values are not touched: they stay the editor's, `7` for a cell that held `007`. KeepCSV is what keeps the file's own text, and this is what is written when it cannot. A field is quoted when the delimiter, a quote or a line end is in it.
Types ¶
type CSVDialect ¶
type CSVDialect struct {
// Comma is the delimiter: ',', ';', '\t' or '|'.
Comma byte
// BOM: the file starts with a byte order mark (UTF-8's, or UTF-16's for a
// UTF-16 file).
BOM bool
// CRLF: its lines end in "\r\n" (else "\n").
CRLF bool
// UTF8: its bytes are UTF-8 (ASCII included). False for UTF-16 and for a
// code page.
UTF8 bool
// Encoding is what it is written in when it is not UTF-8: "utf-16le",
// "utf-16be", or a code page ("windows-1254"), as a browser's TextDecoder
// names them (encoding.go). Empty for UTF-8, and for a file whose encoding
// nobody read (a dialect written by hand).
Encoding string
}
CSVDialect is how a CSV file is written.
func SniffCSV ¶
func SniffCSV(head []byte) CSVDialect
SniffCSV reads how a CSV is written from its first bytes (CSVSniffBytes of them is plenty; fewer is fine). The delimiter is the candidate that splits the first lines (outside quotes) into the same number of fields, the most of them; with none consistent, the most frequent; with none at all, a comma. The encoding: UTF-16 by its byte order mark (or by the zero bytes of its ASCII), UTF-8 when the bytes are, else the code page its letters read best in (detectPage).
func (CSVDialect) Charset ¶
func (d CSVDialect) Charset() string
Charset is the dialect's encoding by its name: "utf-8" for a UTF-8 file, "" when it is not UTF-8 and nobody said what it is.
func (CSVDialect) KeepsBOM ¶
func (d CSVDialect) KeepsBOM() bool
KeepsBOM reports whether the saved file starts with a UTF-8 byte order mark: when the file had one, and when it was not UTF-8 and nobody read what it was (the save is UTF-8 then, and the mark is what tells a reader so). SaveCSV writes a file in its own encoding, with its own mark or none.
func (CSVDialect) Text ¶
func (d CSVDialect) Text() TextDialect
Text is the dialect as an app's interface is told it.
type CSVKept ¶
type CSVKept struct {
// Applied: the cells were kept. False: the bytes are RewriteCSV's.
Applied bool
// Why they were not: "empty" (the file on storage has no record),
// "not_utf8", "too_large", "too_many_records", "too_many_fields" (in one
// record), "check_failed" (the result did not read back as the save),
// "panic".
Why string
// Panic, when Why is "panic": what panicked and where, for the log. A
// runtime panic names indexes, never a cell's text.
Panic string
// Records written.
Records int
// Unchanged records, written from the file's own bytes.
Unchanged int
// Restored cells: in a record somebody changed, the cells whose own text
// was put back over ONLYOFFICE's way of writing it.
Restored int
// New records: saved ones with no record of the file behind them.
New int
// Deleted records: the file's, with no saved record.
Deleted int
// Commas: cells somebody typed or added, numbers ONLYOFFICE wrote with a
// decimal point, written with the decimal comma of their column
// (csvDecimalCommas).
Commas int
}
CSVKept says what KeepCSV did, for the log and the tests.
func KeepCSV ¶
func KeepCSV(original, saved []byte, d CSVDialect) ([]byte, CSVKept)
KeepCSV turns a comma-separated UTF-8 save (Docs 9.4's) into the bytes to write, with the text of every cell nobody changed as it is in original, the file on storage: a record in which nothing changed byte for byte, the unchanged cells of a changed one, new records in the file's dialect. d is how the original is written (SniffCSV). When the cells cannot be kept the bytes are RewriteCSV(saved, d) and CSVKept says why. SaveCSV is the same for a save in any dialect and a file in any encoding.
type CSVSave ¶
type CSVSave struct {
CSVKept
// File is how the written file is written: the file's own dialect (its
// encoding may be another code page that reads the file's bytes alike,
// one that holds the save's letters: alikePages).
File CSVDialect
// Saved is how the editor wrote its save.
Saved CSVDialect
}
CSVSave says what SaveCSV did, for the log and the tests.
func SaveCSV ¶
SaveCSV turns what an editor saved over a .csv into the bytes to write. decl is what the editor declared about its bytes (nil: nothing). An error is a *Refusal - the save must not be written - when the bytes are not what was declared, cannot be read for this file, or hold a character the file's encoding cannot.
When the cells cannot be kept (the file is too large, could not be read whole, ...) the save is still written in the file's way, with the editor's values, and CSVSave.Why says why (P3, csv_keep.go). When nothing of the file could be read, the save is written as the editor wrote it: nothing is guessed about a file nobody could read.
type Declared ¶
type Declared struct {
// Delimiter is its one character, 0 when not said.
Delimiter byte
// Encoding is its name (EncodingLabel's), "" when not said.
Encoding string
// BOM: it starts with a byte order mark; nil when not said.
BOM *bool
// EOL is "crlf" or "lf", "" when not said.
EOL string
}
Declared is what the producer of a save says about how it is written (an app's `csv` save option). A field left out is not said.
func ParseDeclared ¶
ParseDeclared reads a declaration from its four values as an app's save sends them (query csv_delimiter, csv_encoding, csv_bom, csv_eol). nil when none is given.
type Env ¶
type Env struct {
Store Store
Driver storage.Driver
Writer storage.Writer
// Locks is the storage's lock view from the SHARED resolver (api.Deps.ACL):
// a fresh acl.New does not know the vaults, and a name inside a vault
// must be refused here as everywhere.
Locks writegate.Locks
// App is the app writing it (an app's own lock lets it through); 0 for the
// Document Server.
App int64
// MayCreate reports whether the person may create a file at rel now
// (files.create there: role, folder exceptions, grants, a blocked file
// type, an app's lock).
MayCreate func(ctx context.Context, uid int64, rel string) bool
// Sync records the new file in the catalogue; Write emits the one event
// itself, for the people it was written for, with the notice.
Sync *protocolsync.Syncer
// Origin is the event's origin (writehook.OriginOnlyOffice,
// writehook.OriginPlugin).
Origin string
}
Env is where a save is written and who answers for what.
func (Env) BesideTarget ¶
BesideTarget is where an edit of node saved as ext goes: the file's own name with that extension (BesideName), or the next free `name (2).ext`.
func (Env) ConflictTarget ¶
func (e Env) ConflictTarget(ctx context.Context, node *model.Node, ext string, now time.Time) (string, error)
ConflictTarget is where a save of node made while the file changed goes: its conflict copy (ConflictName), in ext when the save is in another format than the file's ("" or the file's own: its own type), free.
type GateError ¶
type GateError struct{ Err error }
GateError is a save writegate refused at its new name: a lock, a name filex keeps, a vault.
type Original ¶
type Original struct {
// Head is its first bytes (CSVSniffBytes at most): how it is written is
// read from them. nil when nothing of it could be read.
Head []byte
// Body is the whole file, nil when it is not held (Why says why).
Body []byte
// Why it is not held: "too_large" (over KeepMaxBytes), "unreadable" (the
// read broke off).
Why string
}
Original is the file a save replaces, as far as it could be read.
func ReadOriginal ¶
ReadOriginal reads the file a save is about to replace: its head, and the whole of it up to KeepMaxBytes. size is its size as the catalogue says it (the buffer's first guess, and a file larger than the bound is not read past its head). The error is a read that broke off, for the log; what was read is in the Original all the same.
func ReadOriginalFrom ¶
ReadOriginalFrom is ReadOriginal of a file the caller opened: err is the opening's (the file could not be opened: nothing of it is read). The error returned is the opening's or the read's, for the caller's log.
type Refusal ¶
type Refusal struct {
// Why:
// - "delimiter", "encoding", "bom", "eol": the producer declared it one
// way and the bytes are written another (Declared, Found);
// - "unreadable": bytes that are not text in an encoding filex can read
// for the file (Found);
// - "unencodable": the file is in Encoding, which cannot hold Char;
// - "package": a spreadsheet package (XLSX, ODS, XLS) where CSV text
// belongs.
Why string
// Declared and Found, as a person reads them: `;`, `TAB`, `utf-8`,
// `CRLF`, `yes`/`no` for a byte order mark.
Declared, Found string
// Encoding is the file's encoding, for "unencodable".
Encoding string
// Char is the first character the file's encoding cannot hold.
Char rune
}
Refusal is a CSV save that is not written, and why. The file does not change; the caller tells the person who saved it.
type Save ¶
type Save struct {
// Target is the name it is written under (Env.BesideTarget,
// Env.ConflictTarget).
Target string
// Format is the type the bytes are in.
Format string
Mime string
// TitleKey, BodyKey and Vars are what the people it was written for are
// told (srvtext keys, every built-in language into the notice's meta).
TitleKey string
BodyKey string
Vars srvtext.Vars
// Action is the audit row's action.
Action string
// Why is the log line's reason.
Why string
}
Save is one save written beside its document.
type Store ¶
type Store interface {
GetNodeByPath(ctx context.Context, storageID int64, pathHash string) (*model.Node, error)
GetStorage(ctx context.Context, id int64) (*model.Storage, error)
GetUser(ctx context.Context, id int64) (*model.User, error)
InsertAuditEntry(ctx context.Context, e *model.AuditEntry) error
}
Store is what a save written beside its document reads and writes in the catalogue (db.Store has every method).
type TextDialect ¶
type TextDialect struct {
// Delimiter is one character: ",", ";", "\t" or "|".
Delimiter string `json:"delimiter"`
// BOM: the file starts with a byte order mark.
BOM bool `json:"bom"`
// CRLF: its lines end in "\r\n".
CRLF bool `json:"crlf"`
// Encoding is its encoding's name as a browser's TextDecoder takes it:
// "utf-8", "utf-16le", "utf-16be", "windows-1254"...
Encoding string `json:"encoding"`
}
TextDialect is how a CSV is written, as an app's interface is told it (`text_dialect`).
type Written ¶
type Written struct {
// Node is the new file's catalogue row.
Node *model.Node
Size int64
// For are the people it was written for, the one who may create it first.
For []int64
}
Written is a save written beside its document.
func Write ¶
func Write(ctx context.Context, env Env, node *model.Node, src io.Reader, length int64, who []int64, s Save) (*Written, error)
Write writes src at s.Target, beside node, which is left as it was, for the first of who that may create it there, checked now, and tells them. The gate is asked for the new name as for every save (syspath.SaveVerb: a draft's owner, a desktop working copy). err is ErrNoEditor, ErrNoCreate, a *GateError, or a failure to write.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package officesavetest holds what a real ONLYOFFICE Document Server saved, byte for byte, for the tests of the packages that keep a saved CSV in its file's way (officesave, onlyoffice).
|
Package officesavetest holds what a real ONLYOFFICE Document Server saved, byte for byte, for the tests of the packages that keep a saved CSV in its file's way (officesave, onlyoffice). |