Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -0.19.0 +0.20.0-dev Index: box/constbox/constbox.go ================================================================== --- box/constbox/constbox.go +++ box/constbox/constbox.go @@ -409,15 +409,16 @@ api.KeyVisibility: api.ValueVisibilityLogin, }, zettel.NewContent(nil)}, id.DefaultHomeZid: { constHeader{ - api.KeyTitle: "Home", - api.KeyRole: api.ValueRoleZettel, - api.KeySyntax: meta.SyntaxZmk, - api.KeyLang: api.ValueLangEN, - api.KeyCreated: "20210210190757", + api.KeyTitle: "Home", + api.KeyRole: api.ValueRoleZettel, + api.KeySyntax: meta.SyntaxZmk, + api.KeyLang: api.ValueLangEN, + api.KeyCreated: "20210210190757", + api.KeyModified: "20241216105800", }, zettel.NewContent(contentHomeZettel)}, } //go:embed license.txt Index: box/constbox/home.zettel ================================================================== --- box/constbox/home.zettel +++ box/constbox/home.zettel @@ -1,15 +1,14 @@ === Thank you for using Zettelstore! You will find the lastest information about Zettelstore at [[https://zettelstore.de]]. -Check that website regulary for [[upgrades|https://zettelstore.de/home/doc/trunk/www/download.wiki]] to the latest version. -You should consult the [[change log|https://zettelstore.de/home/doc/trunk/www/changes.wiki]] before upgrading. -Sometimes, you have to edit some of your Zettelstore-related zettel before upgrading. -Since Zettelstore is currently in a development state, every upgrade might fix some of your problems. +Check this website regularly for [[updates|https://zettelstore.de/home/doc/trunk/www/download.wiki]] to the latest version. +You should consult the [[change log|https://zettelstore.de/home/doc/trunk/www/changes.wiki]] before updating. +Sometimes, you have to edit some of your Zettelstore-related zettel before updating. +Since Zettelstore is currently in a development state, every update might fix some of your problems. -If you have problems concerning Zettelstore, -do not hesitate to get in [[contact with the main developer|mailto:ds@zettelstore.de]]. +If you have problems concerning Zettelstore, do not hesitate to get in [[contact with the main developer|mailto:ds@zettelstore.de]]. === Reporting errors If you have encountered an error, please include the content of the following zettel in your mail (if possible): * [[Zettelstore Version|00000000000001]]: {{00000000000001}} * [[Zettelstore Operating System|00000000000003]] Index: box/manager/box.go ================================================================== --- box/manager/box.go +++ box/manager/box.go @@ -63,15 +63,15 @@ } mgr.mgrMx.RLock() defer mgr.mgrMx.RUnlock() if box, isWriteBox := mgr.boxes[0].(box.WriteBox); isWriteBox { ztl.Meta = mgr.cleanMetaProperties(ztl.Meta) - zidO, err := box.CreateZettel(ctx, ztl) + zid, err := box.CreateZettel(ctx, ztl) if err == nil { mgr.idxUpdateZettel(ctx, ztl) } - return zidO, err + return zid, err } return id.Invalid, box.ErrReadOnly } // GetZettel retrieves a specific zettel. @@ -140,16 +140,10 @@ } } return result, nil } -// FetchZidsO returns the set of all old-style zettel identifer managed by the box. -func (mgr *Manager) FetchZidsO(ctx context.Context) (*id.Set, error) { - mgr.mgrLog.Debug().Msg("FetchZidsO") - return mgr.fetchZids(ctx) -} - func (mgr *Manager) hasZettel(ctx context.Context, zid id.Zid) bool { mgr.mgrLog.Debug().Zid(zid).Msg("HasZettel") if err := mgr.checkContinue(ctx); err != nil { return false } @@ -280,29 +274,29 @@ } return false } // DeleteZettel removes the zettel from the box. -func (mgr *Manager) DeleteZettel(ctx context.Context, zidO id.Zid) error { - mgr.mgrLog.Debug().Zid(zidO).Msg("DeleteZettel") +func (mgr *Manager) DeleteZettel(ctx context.Context, zid id.Zid) error { + mgr.mgrLog.Debug().Zid(zid).Msg("DeleteZettel") if err := mgr.checkContinue(ctx); err != nil { return err } mgr.mgrMx.RLock() defer mgr.mgrMx.RUnlock() for _, p := range mgr.boxes { - err := p.DeleteZettel(ctx, zidO) + err := p.DeleteZettel(ctx, zid) if err == nil { - mgr.idxDeleteZettel(ctx, zidO) + mgr.idxDeleteZettel(ctx, zid) return err } var errZNF box.ErrZettelNotFound if !errors.As(err, &errZNF) && !errors.Is(err, box.ErrReadOnly) { return err } } - return box.ErrZettelNotFound{Zid: zidO} + return box.ErrZettelNotFound{Zid: zid} } // Remove all (computed) properties from metadata before storing the zettel. func (mgr *Manager) cleanMetaProperties(m *meta.Meta) *meta.Meta { result := m.Clone() Index: box/manager/manager.go ================================================================== --- box/manager/manager.go +++ box/manager/manager.go @@ -247,22 +247,22 @@ reason: reason, } return false } -func (mgr *Manager) idxEnqueue(reason box.UpdateReason, zidO id.Zid) { +func (mgr *Manager) idxEnqueue(reason box.UpdateReason, zid id.Zid) { switch reason { case box.OnReady: return case box.OnReload: mgr.idxAr.Reset() case box.OnZettel: - mgr.idxAr.EnqueueZettel(zidO) + mgr.idxAr.EnqueueZettel(zid) case box.OnDelete: - mgr.idxAr.EnqueueZettel(zidO) + mgr.idxAr.EnqueueZettel(zid) default: - mgr.mgrLog.Error().Uint("reason", uint64(reason)).Zid(zidO).Msg("Unknown notification reason") + mgr.mgrLog.Error().Uint("reason", uint64(reason)).Zid(zid).Msg("Unknown notification reason") return } select { case mgr.idxReady <- struct{}{}: default: Index: docs/manual/00001007031140.zettel ================================================================== --- docs/manual/00001007031140.zettel +++ docs/manual/00001007031140.zettel @@ -2,11 +2,11 @@ title: Zettelmarkup: Query Transclusion role: manual tags: #manual #search #zettelmarkup #zettelstore syntax: zmk created: 20220809132350 -modified: 20240219161800 +modified: 20241213153229 A query transclusion is specified by the following sequence, starting at the first position in a line: ''{{{query:query-expression}}}''. The line must literally start with the sequence ''{{{query:''. Everything after this prefix is interpreted as a [[query expression|00001007700000]]. @@ -36,19 +36,10 @@ : Emit only those values with at least __n__ aggregated values. __n__ must be a positive integer, ''MIN'' must be given in upper-case letters. ; ''MAXn'' (parameter) : Emit only those values with at most __n__ aggregated values. __n__ must be a positive integer, ''MAX'' must be given in upper-case letters. -; ''TITLE'' (parameter) -: All words following ''TITLE'' are joined together to form a title. - It is used for the ''ATOM'' and ''RSS'' action. -; ''ATOM'' (aggregate) -: Transform the zettel list into an [[Atom 1.0|https://www.rfc-editor.org/rfc/rfc4287]]-conformant document / feed. - The document is embedded into the referencing zettel. -; ''RSS'' (aggregate) -: Transform the zettel list into a [[RSS 2.0|https://www.rssboard.org/rss-specification]]-conformant document / feed. - The document is embedded into the referencing zettel. ; ''KEYS'' (aggregate) : Emit a list of all metadata keys, together with the number of zettel having the key. ; ''REDIRECT'', ''REINDEX'' (aggregate) : Will be ignored. These actions may have been copied from an existing [[API query call|00001012051400]] (or from a WebUI query), but are here superfluous (and possibly harmful). Index: docs/manual/00001007780000.zettel ================================================================== --- docs/manual/00001007780000.zettel +++ docs/manual/00001007780000.zettel @@ -2,11 +2,11 @@ title: Formal syntax of query expressions role: manual tags: #manual #reference #search #zettelstore syntax: zmk created: 20220810144539 -modified: 20240219155949 +modified: 20241213153200 ``` QueryExpression := ZettelList? QueryDirective* SearchExpression ActionExpression? ZettelList := (ZID (SPACE+ ZID)*). ZID := '0'+ ('1' .. '9'') DIGIT* @@ -42,16 +42,13 @@ | '!' '?'. PosInt := '0' | ('1' .. '9') DIGIT*. ActionExpression := '|' (Word (SPACE+ Word)*)? Action := Word - | 'ATOM' | 'KEYS' | 'N' NO-SPACE* | 'MAX' PosInt | 'MIN' PosInt | 'REDIRECT' - | 'REINDEX' - | 'RSS' - | 'TITLE' (SPACE Word)* . + | 'REINDEX'. Word := NO-SPACE NO-SPACE* ``` Index: docs/manual/00001012051200.zettel ================================================================== --- docs/manual/00001012051200.zettel +++ docs/manual/00001012051200.zettel @@ -2,13 +2,13 @@ title: API: List all zettel role: manual tags: #api #manual #zettelstore syntax: zmk created: 20210126175322 -modified: 20230807170810 +modified: 20241216104355 -To list all zettel just send a HTTP GET request to the [[endpoint|00001012920000]] ''/z''[^If [[authentication is enabled|00001010040100]], you must include the a valid [[access token|00001012050200]] in the ''Authorization'' header]. +To list all zettel just send a HTTP GET request to the [[endpoint|00001012920000]] ''/z''[^If [[authentication is enabled|00001010040100]], you must include a valid [[access token|00001012050200]] in the ''Authorization'' header]. Always use the endpoint ''/z'' to work with a list of zettel. Without further specifications, a plain text document is returned, with one line per zettel. Each line contains in the first 14 characters the [[zettel identifier|00001006050000]]. Separated by a space character, the title of the zettel follows: Index: docs/manual/00001012051400.zettel ================================================================== --- docs/manual/00001012051400.zettel +++ docs/manual/00001012051400.zettel @@ -2,14 +2,14 @@ title: API: Query the list of all zettel role: manual tags: #api #manual #zettelstore syntax: zmk created: 20220912111111 -modified: 20240711161320 +modified: 20241216104329 precursor: 00001012051200 -The [[endpoint|00001012920000]] ''/z'' also allows you to filter the list of all zettel[^If [[authentication is enabled|00001010040100]], you must include the a valid [[access token|00001012050200]] in the ''Authorization'' header] and optionally to provide some actions. +The [[endpoint|00001012920000]] ''/z'' also allows you to filter the list of all zettel[^If [[authentication is enabled|00001010040100]], you must include a valid [[access token|00001012050200]] in the ''Authorization'' header] and optionally to provide some actions. A [[query|00001007700000]] is an optional [[search expression|00001007700000#search-expression]], together with an optional [[list of actions|00001007700000#action-list]] (described below). An empty search expression will select all zettel. An empty list of action, or no valid action, returns the list of all selected zettel metadata. Index: docs/manual/00001012053300.zettel ================================================================== --- docs/manual/00001012053300.zettel +++ docs/manual/00001012053300.zettel @@ -2,21 +2,21 @@ title: API: Retrieve metadata and content of an existing zettel role: manual tags: #api #manual #zettelstore syntax: zmk created: 20211004093206 -modified: 20230807170259 +modified: 20241216104429 The [[endpoint|00001012920000]] to work with metadata and content of a specific zettel is ''/z/{ID}'', where ''{ID}'' is a placeholder for the [[zettel identifier|00001006050000]]. -For example, to retrieve some data about this zettel you are currently viewing, just send a HTTP GET request to the endpoint ''/z/00001012053300''[^If [[authentication is enabled|00001010040100]], you must include the a valid [[access token|00001012050200]] in the ''Authorization'' header]. +For example, to retrieve some data about this zettel you are currently viewing, just send a HTTP GET request to the endpoint ''/z/00001012053300''[^If [[authentication is enabled|00001010040100]], you must include a valid [[access token|00001012050200]] in the ''Authorization'' header]. ````sh # curl 'http://127.0.0.1:23123/z/00001012053300' The [[endpoint|00001012920000]] to work with metadata and content of a specific zettel is ''/z/{ID}'', where ''{ID}'' is a placeholder for the [[zettel identifier|00001006050000]]. -For example, to retrieve some data about this zettel you are currently viewing, just send a HTTP GET request to the endpoint ''/z/00001012053300''[^If [[authentication is enabled|00001010040100]], you must include the a valid [[access token|00001012050200]] in the ''Authorization'' header]. +For example, to retrieve some data about this zettel you are currently viewing, just send a HTTP GET request to the endpoint ''/z/00001012053300''[^If [[authentication is enabled|00001010040100]], you must include a valid [[access token|00001012050200]] in the ''Authorization'' header]. ```sh ... ```` Index: docs/manual/00001012053400.zettel ================================================================== --- docs/manual/00001012053400.zettel +++ docs/manual/00001012053400.zettel @@ -2,13 +2,13 @@ title: API: Retrieve metadata of an existing zettel role: manual tags: #api #manual #zettelstore syntax: zmk created: 20210726174524 -modified: 20230807170155 +modified: 20241216104120 -The [[endpoint|00001012920000]] to work with metadata of a specific zettel is ''/z/{ID}'', where ''{ID}'' is a placeholder for the [[zettel identifier|00001006050000]][^If [[authentication is enabled|00001010040100]], you must include the a valid [[access token|00001012050200]] in the ''Authorization'' header]. +The [[endpoint|00001012920000]] to work with metadata of a specific zettel is ''/z/{ID}'', where ''{ID}'' is a placeholder for the [[zettel identifier|00001006050000]][^If [[authentication is enabled|00001010040100]], you must include a valid [[access token|00001012050200]] in the ''Authorization'' header]. To retrieve the plain metadata of a zettel, use the query parameter ''part=meta'' ````sh # curl 'http://127.0.0.1:23123/z/00001012053400?part=meta' Index: docs/manual/00001012053500.zettel ================================================================== --- docs/manual/00001012053500.zettel +++ docs/manual/00001012053500.zettel @@ -2,15 +2,15 @@ title: API: Retrieve evaluated metadata and content of an existing zettel in various encodings role: manual tags: #api #manual #zettelstore syntax: zmk created: 20210726174524 -modified: 20240620171057 +modified: 20241216104145 The [[endpoint|00001012920000]] to work with evaluated metadata and content of a specific zettel is ''/z/{ID}'', where ''{ID}'' is a placeholder for the [[zettel identifier|00001006050000]]. -For example, to retrieve some evaluated data about this zettel you are currently viewing in [[Sz encoding|00001012920516]], just send a HTTP GET request to the endpoint ''/z/00001012053500''[^If [[authentication is enabled|00001010040100]], you must include the a valid [[access token|00001012050200]] in the ''Authorization'' header] with the query parameter ''enc=sz''. +For example, to retrieve some evaluated data about this zettel you are currently viewing in [[Sz encoding|00001012920516]], just send a HTTP GET request to the endpoint ''/z/00001012053500''[^If [[authentication is enabled|00001010040100]], you must include a valid [[access token|00001012050200]] in the ''Authorization'' header] with the query parameter ''enc=sz''. If successful, the output is a symbolic expression value: ```sh # curl 'http://127.0.0.1:23123/z/00001012053500?enc=sz' (BLOCK (PARA (TEXT "The ") (LINK-ZETTEL () "00001012920000" (TEXT "endpoint")) (TEXT " to work with parsed metadata and content of a specific zettel is ") (LITERAL-INPUT () "/z/{ID}") (TEXT ", where ") (LITERAL-INPUT () "{ID}") (TEXT " is a placeholder for the ") ... ``` Index: docs/manual/00001012053600.zettel ================================================================== --- docs/manual/00001012053600.zettel +++ docs/manual/00001012053600.zettel @@ -2,18 +2,18 @@ title: API: Retrieve parsed metadata and content of an existing zettel in various encodings role: manual tags: #api #manual #zettelstore syntax: zmk created: 20210126175322 -modified: 20240620170909 +modified: 20241216104306 The [[endpoint|00001012920000]] to work with parsed metadata and content of a specific zettel is ''/z/{ID}'', where ''{ID}'' is a placeholder for the [[zettel identifier|00001006050000]]. A __parsed__ zettel is basically an [[unevaluated|00001012053500]] zettel: the zettel is read and analyzed, but its content is not __evaluated__. By using this endpoint, you are able to retrieve the structure of a zettel before it is evaluated. -For example, to retrieve some data about this zettel you are currently viewing, just send a HTTP GET request to the endpoint ''/z/00001012053600''[^If [[authentication is enabled|00001010040100]], you must include the a valid [[access token|00001012050200]] in the ''Authorization'' header] with the query parameter ''parseonly'' (and other appropriate query parameter). +For example, to retrieve some data about this zettel you are currently viewing, just send a HTTP GET request to the endpoint ''/z/00001012053600''[^If [[authentication is enabled|00001010040100]], you must include a valid [[access token|00001012050200]] in the ''Authorization'' header] with the query parameter ''parseonly'' (and other appropriate query parameter). For example: ```sh # curl 'http://127.0.0.1:23123/z/00001012053600?enc=sz&parseonly' (BLOCK (PARA (TEXT "The ") (LINK-ZETTEL () "00001012920000" (TEXT "endpoint")) (TEXT " to work with parsed metadata and content of a specific zettel is ") (LITERAL-INPUT () "/z/{ID}") (TEXT ", where ") ... ``` Index: docs/manual/00001012080200.zettel ================================================================== --- docs/manual/00001012080200.zettel +++ docs/manual/00001012080200.zettel @@ -2,13 +2,13 @@ title: API: Check for authentication role: manual tags: #api #manual #zettelstore syntax: zmk created: 20220103224858 -modified: 20220908163156 +modified: 20241216104549 -API clients typically wants to know, whether [[authentication is enabled|00001010040100]] or not. +API clients typically want to know, whether [[authentication is enabled|00001010040100]] or not. If authentication is enabled, they present some form of user interface to get user name and password for the actual authentication. Then they try to [[obtain an access token|00001012050200]]. If authentication is disabled, these steps are not needed. To check for enabled authentication, you must send a HTTP POST request to the [[endpoint|00001012920000]] ''/x'' and you must specify the query parameter ''cmd=authenticated''. Index: docs/manual/00001012080500.zettel ================================================================== --- docs/manual/00001012080500.zettel +++ docs/manual/00001012080500.zettel @@ -2,16 +2,16 @@ title: API: Refresh internal data role: manual tags: #api #manual #zettelstore syntax: zmk created: 20211230230441 -modified: 20220923104836 +modified: 20241216104624 Zettelstore maintains some internal data to allow faster operations. One example is the [[content search|00001012051400]] for a term: Zettelstore does not need to scan all zettel to find all occurrences for the term. -Instead, all word are stored internally, with a list of zettel where they occur. +Instead, all words are stored internally, with a list of zettel where they occur. Another example is the way to determine which zettel are stored in a [[ZIP file|00001004011200]]. Scanning a ZIP file is a lengthy operation, therefore Zettelstore maintains a directory of zettel for each ZIP file. All these internal data may become stale. Index: docs/manual/00001012931400.zettel ================================================================== --- docs/manual/00001012931400.zettel +++ docs/manual/00001012931400.zettel @@ -2,11 +2,11 @@ title: Encoding of Sz Block Elements role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161803 -modified: 20240123120132 +modified: 20241216104739 === ''PARA'' :::syntax __Paragraph__ **=** ''(PARA'' [[__InlineElement__|00001012931600]] … '')''. ::: @@ -45,11 +45,11 @@ If it is a block, it may contain a nested list. === ''DESCRIPTION'' :::syntax __Description__ **=** ''(DESCRIPTION'' __DescriptionTerm__ __DescriptionValues__ __DescriptionTerm__ __DescriptionValues__ … '')''. ::: -A description is a sequence of one ore more terms and values. +A description is a sequence of one or more terms and values. :::syntax __DescriptionTerm__ **=** ''('' [[__InlineElement__|00001012931600]] … '')''. ::: A description term is just an inline-structured value. @@ -124,11 +124,11 @@ :::syntax __VerseRegion__ **=** ''(REGION-VERSE'' [[__Attributes__|00001012931000#attribute]] ''('' [[__BlockElement__|00001012931400]] … '')'' [[__InlineElement__|00001012931600]] … '')''. ::: A block region just treats the block to contain a verse. -Soft line break are transformed into hard line breaks to save the structure of the verse / poem. +Soft line breaks are transformed into hard line breaks to save the structure of the verse / poem. Attributes may further specify something. The inline typically describes author / source of the verse. === ''VERBATIM-*'' The following lists specifies some literal text of more than one line. Index: docs/manual/00001012931600.zettel ================================================================== --- docs/manual/00001012931600.zettel +++ docs/manual/00001012931600.zettel @@ -2,11 +2,11 @@ title: Encoding of Sz Inline Elements role: manual tags: #api #manual #reference #zettelstore syntax: zmk created: 20230403161845 -modified: 20240620170546 +modified: 20241216104906 === ''TEXT'' :::syntax __Text__ **=** ''(TEXT'' String '')''. ::: @@ -94,11 +94,11 @@ __EmbedBLOB__ **=** ''(EMBED-BLOB'' [[__Attributes__|00001012931000#attribute]] String,,1,, String,,2,, '')''. ::: If used if some processed image has to be embedded inside some inline material. The first string specifies the syntax of the image content. The second string contains the image content. -If the syntax is ""SVG"", the image content is not further encoded. +If the syntax is ""SVG"", the image content is not encoded further. Otherwise a base64 encoding is used. === ''CITE'' :::syntax __CiteBLOB__ **=** ''(CITE'' [[__Attributes__|00001012931000#attribute]] String [[__InlineElement__|00001012931600]] … '')''. @@ -140,11 +140,11 @@ The inline text should be treated as inserted. :::syntax __MarkFormat__ **=** ''(FORMAT-MARK'' [[__Attributes__|00001012931000#attribute]] [[__InlineElement__|00001012931600]] … '')''. ::: -The inline text should be treated as highlighted for the reader (but was not important fto the original author). +The inline text should be treated as highlighted for the reader (but was not important to the original author). :::syntax __QuoteFormat__ **=** ''(FORMAT-QUOTE'' [[__Attributes__|00001012931000#attribute]] [[__InlineElement__|00001012931600]] … '')''. ::: The inline text should be treated as quoted text. Index: docs/manual/00001017000000.zettel ================================================================== --- docs/manual/00001017000000.zettel +++ docs/manual/00001017000000.zettel @@ -2,11 +2,11 @@ title: Tips and Tricks role: manual tags: #manual #zettelstore syntax: zmk created: 20220803170112 -modified: 20231012154803 +modified: 20241216105111 === Welcome Zettel * **Problem:** You want to put your Zettelstore into the public and need a starting zettel for your users. In addition, you still want a ""home zettel"", with all your references to internal, non-public zettel. Zettelstore only allows to specify one [[''home-zettel''|00001004020000#home-zettel]]. @@ -67,14 +67,14 @@ ''zettelstore run -d ~/Library/Mobile\\ Documents/com\\~apple\\~CloudDocs/zettel'' (The ""''\\''"" is needed by the command line processor to mask the following character to be processed in unintended ways.) * **Discussion:** Zettel files are synchronized between your computers via iCloud. - Is does not matter, if one of your computer is offline / switched off. + Is does not matter, if one of your computers is offline or switched off. iCloud will synchronize the zettel files if it later comes online. However, if you use more than one computer simultaneously, you must be aware that synchronization takes some time. - It might take several seconds, maybe longer, that new new version of a zettel appears on the other computer. + It might take several seconds, maybe longer, that the new version of a zettel appears on the other computer. If you update the same zettel on multiple computers at nearly the same time, iCloud will not be able to synchronize the different versions in a safe manner. Zettelstore is intentionally not aware of any synchronization within its zettel boxes. If Zettelstore behaves strangely after a synchronization took place, the page about [[Troubleshooting|00001018000000#working-with-files]] might contain some useful information. DELETED encoding/atom/atom.go Index: encoding/atom/atom.go ================================================================== --- encoding/atom/atom.go +++ /dev/null @@ -1,123 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2022-present Detlef Stern -// -// This file is part of Zettelstore. -// -// Zettelstore is licensed under the latest version of the EUPL (European Union -// Public License). Please see file LICENSE.txt for your rights and obligations -// under this license. -// -// SPDX-License-Identifier: EUPL-1.2 -// SPDX-FileCopyrightText: 2022-present Detlef Stern -//----------------------------------------------------------------------------- - -// Package atom provides an Atom encoding. -package atom - -import ( - "bytes" - "time" - - "t73f.de/r/zsc/api" - "zettelstore.de/z/config" - "zettelstore.de/z/encoding" - "zettelstore.de/z/encoding/xml" - "zettelstore.de/z/kernel" - "zettelstore.de/z/query" - "zettelstore.de/z/strfun" - "zettelstore.de/z/zettel/id" - "zettelstore.de/z/zettel/meta" -) - -// ContentType specifies the HTTP content type for Atom. -const ContentType = "application/atom+xml" - -// Configuration contains data to configure the Atom encoding. -type Configuration struct { - Title string - Generator string - NewURLBuilderAbs func() *api.URLBuilder -} - -// Setup initializes the Configuration. -func (c *Configuration) Setup(cfg config.Config) { - baseURL := kernel.Main.GetConfig(kernel.WebService, kernel.WebBaseURL).(string) - - c.Title = cfg.GetSiteName() - c.Generator = (kernel.Main.GetConfig(kernel.CoreService, kernel.CoreProgname).(string) + - " " + - kernel.Main.GetConfig(kernel.CoreService, kernel.CoreVersion).(string)) - c.NewURLBuilderAbs = func() *api.URLBuilder { return api.NewURLBuilder(baseURL, 'h') } -} - -// Marshal encodes the result of a query as Atom. -func (c *Configuration) Marshal(q *query.Query, ml []*meta.Meta) []byte { - atomUpdated := encoding.LastUpdated(ml, time.RFC3339) - feedLink := c.NewURLBuilderAbs().String() - - var buf bytes.Buffer - buf.WriteString(`` + "\n") - xml.WriteTag(&buf, " ", "title", c.Title) - xml.WriteTag(&buf, " ", "id", feedLink) - buf.WriteString(` ` + "\n") - if atomUpdated != "" { - xml.WriteTag(&buf, " ", "updated", atomUpdated) - } - xml.WriteTag(&buf, " ", "generator", c.Generator) - buf.WriteString(" Unknown\n") - - for _, m := range ml { - c.marshalMeta(&buf, m) - } - - buf.WriteString("") - return buf.Bytes() -} - -func (c *Configuration) marshalMeta(buf *bytes.Buffer, m *meta.Meta) { - entryUpdated := "" - if val, found := m.Get(api.KeyPublished); found { - if published, err := time.ParseInLocation(id.TimestampLayout, val, time.Local); err == nil { - entryUpdated = published.UTC().Format(time.RFC3339) - } - } - - link := c.NewURLBuilderAbs().SetZid(m.Zid.ZettelID()).String() - - buf.WriteString(" \n") - xml.WriteTag(buf, " ", "title", encoding.TitleAsText(m)) - xml.WriteTag(buf, " ", "id", link) - buf.WriteString(` ` + "\n") - buf.WriteString(` ` + "\n") - - if entryUpdated != "" { - xml.WriteTag(buf, " ", "updated", entryUpdated) - } - marshalTags(buf, m) - buf.WriteString(" \n") -} - -func marshalTags(buf *bytes.Buffer, m *meta.Meta) { - if tags, found := m.GetList(api.KeyTags); found && len(tags) > 0 { - for _, tag := range tags { - for len(tag) > 0 && tag[0] == '#' { - tag = tag[1:] - } - if tag != "" { - buf.WriteString(` \n") - } - } - } -} DELETED encoding/encoding.go Index: encoding/encoding.go ================================================================== --- encoding/encoding.go +++ /dev/null @@ -1,45 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2022-present Detlef Stern -// -// This file is part of Zettelstore. -// -// Zettelstore is licensed under the latest version of the EUPL (European Union -// Public License). Please see file LICENSE.txt for your rights and obligations -// under this license. -// -// SPDX-License-Identifier: EUPL-1.2 -// SPDX-FileCopyrightText: 2022-present Detlef Stern -//----------------------------------------------------------------------------- - -// Package encoding provides helper functions for encodings. -package encoding - -import ( - "time" - - "t73f.de/r/zsc/api" - "zettelstore.de/z/parser" - "zettelstore.de/z/zettel/id" - "zettelstore.de/z/zettel/meta" -) - -// LastUpdated returns the formated time of the zettel which was updated at the latest time. -func LastUpdated(ml []*meta.Meta, timeFormat string) string { - maxPublished := time.Date(1, time.January, 1, 0, 0, 0, 0, time.Local) - for _, m := range ml { - if val, found := m.Get(api.KeyPublished); found { - if published, err := time.ParseInLocation(id.TimestampLayout, val, time.Local); err == nil { - if maxPublished.Before(published) { - maxPublished = published - } - } - } - } - if maxPublished.Year() > 1 { - return maxPublished.UTC().Format(timeFormat) - } - return "" -} - -// TitleAsText returns the title of a zettel as plain text -func TitleAsText(m *meta.Meta) string { return parser.NormalizedSpacedText(m.GetTitle()) } DELETED encoding/rss/rss.go Index: encoding/rss/rss.go ================================================================== --- encoding/rss/rss.go +++ /dev/null @@ -1,125 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2022-present Detlef Stern -// -// This file is part of Zettelstore. -// -// Zettelstore is licensed under the latest version of the EUPL (European Union -// Public License). Please see file LICENSE.txt for your rights and obligations -// under this license. -// -// SPDX-License-Identifier: EUPL-1.2 -// SPDX-FileCopyrightText: 2022-present Detlef Stern -//----------------------------------------------------------------------------- - -// Package rss provides a RSS encoding. -package rss - -import ( - "bytes" - "context" - "time" - - "t73f.de/r/zsc/api" - "zettelstore.de/z/config" - "zettelstore.de/z/encoding" - "zettelstore.de/z/encoding/xml" - "zettelstore.de/z/kernel" - "zettelstore.de/z/query" - "zettelstore.de/z/strfun" - "zettelstore.de/z/zettel/id" - "zettelstore.de/z/zettel/meta" -) - -// ContentType specifies the HTTP content type for RSS. -const ContentType = "application/rss+xml" - -// Configuration contains data to configure the RSS encoding. -type Configuration struct { - Title string - Language string - Copyright string - Generator string - NewURLBuilderAbs func() *api.URLBuilder -} - -// Setup initializes the Configuration. -func (c *Configuration) Setup(ctx context.Context, cfg config.Config) { - baseURL := kernel.Main.GetConfig(kernel.WebService, kernel.WebBaseURL).(string) - defVals := cfg.AddDefaultValues(ctx, &meta.Meta{}) - - c.Title = cfg.GetSiteName() - c.Language = defVals.GetDefault(api.KeyLang, "") - c.Copyright = defVals.GetDefault(api.KeyCopyright, "") - c.Generator = (kernel.Main.GetConfig(kernel.CoreService, kernel.CoreProgname).(string) + - " " + - kernel.Main.GetConfig(kernel.CoreService, kernel.CoreVersion).(string)) - c.NewURLBuilderAbs = func() *api.URLBuilder { return api.NewURLBuilder(baseURL, 'h') } -} - -// Marshal encodes the result of a query as Atom. -func (c *Configuration) Marshal(q *query.Query, ml []*meta.Meta) []byte { - rssPublished := encoding.LastUpdated(ml, time.RFC1123Z) - - atomLink := "" - if s := q.String(); s != "" { - atomLink = c.NewURLBuilderAbs().AppendQuery(s).String() - } - var buf bytes.Buffer - buf.WriteString(`` + "\n\n") - xml.WriteTag(&buf, " ", "title", c.Title) - xml.WriteTag(&buf, " ", "link", c.NewURLBuilderAbs().String()) - xml.WriteTag(&buf, " ", "description", "") - xml.WriteTag(&buf, " ", "language", c.Language) - xml.WriteTag(&buf, " ", "copyright", c.Copyright) - if rssPublished != "" { - xml.WriteTag(&buf, " ", "pubDate", rssPublished) - xml.WriteTag(&buf, " ", "lastBuildDate", rssPublished) - } - xml.WriteTag(&buf, " ", "generator", c.Generator) - buf.WriteString(" https://www.rssboard.org/rss-specification\n") - if atomLink != "" { - buf.WriteString(` ` + "\n") - } - for _, m := range ml { - c.marshalMeta(&buf, m) - } - - buf.WriteString("\n") - return buf.Bytes() -} - -func (c *Configuration) marshalMeta(buf *bytes.Buffer, m *meta.Meta) { - itemPublished := "" - if val, found := m.Get(api.KeyPublished); found { - if published, err := time.ParseInLocation(id.TimestampLayout, val, time.Local); err == nil { - itemPublished = published.UTC().Format(time.RFC1123Z) - } - } - - link := c.NewURLBuilderAbs().SetZid(m.Zid.ZettelID()).String() - - buf.WriteString(" \n") - xml.WriteTag(buf, " ", "title", encoding.TitleAsText(m)) - xml.WriteTag(buf, " ", "link", link) - xml.WriteTag(buf, " ", "guid", link) - if itemPublished != "" { - xml.WriteTag(buf, " ", "pubDate", itemPublished) - } - marshalTags(buf, m) - buf.WriteString(" \n") -} - -func marshalTags(buf *bytes.Buffer, m *meta.Meta) { - if tags, found := m.GetList(api.KeyTags); found && len(tags) > 0 { - for _, tag := range tags { - for len(tag) > 0 && tag[0] == '#' { - tag = tag[1:] - } - if tag != "" { - xml.WriteTag(buf, " ", "category", tag) - } - } - } -} DELETED encoding/xml/xml.go Index: encoding/xml/xml.go ================================================================== --- encoding/xml/xml.go +++ /dev/null @@ -1,36 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2022-present Detlef Stern -// -// This file is part of Zettelstore. -// -// Zettelstore is licensed under the latest version of the EUPL (European Union -// Public License). Please see file LICENSE.txt for your rights and obligations -// under this license. -// -// SPDX-License-Identifier: EUPL-1.2 -// SPDX-FileCopyrightText: 2022-present Detlef Stern -//----------------------------------------------------------------------------- - -// Package xml provides helper for a XML-based encoding. -package xml - -import ( - "bytes" - - "zettelstore.de/z/strfun" -) - -// Header contains the string that should start all XML documents. -const Header = `` + "\n" - -// WriteTag writes a simple XML tag with a given prefix and a specific value. -func WriteTag(buf *bytes.Buffer, prefix, tag, value string) { - buf.WriteString(prefix) - buf.WriteByte('<') - buf.WriteString(tag) - buf.WriteByte('>') - strfun.XMLEscape(buf, value) - buf.WriteString("\n") -} Index: evaluator/evaluator.go ================================================================== --- evaluator/evaluator.go +++ evaluator/evaluator.go @@ -294,11 +294,11 @@ if errors.Is(err, &box.ErrNotAllowed{}) { return nil } return makeBlockNode(createInlineErrorText(nil, "Unable", "to", "search", "zettel")) } - result, _ := QueryAction(e.ctx, q, ml, e.rtConfig) + result, _ := QueryAction(e.ctx, q, ml) if result != nil { ast.Walk(e, result) } return result } Index: evaluator/list.go ================================================================== --- evaluator/list.go +++ evaluator/list.go @@ -22,36 +22,32 @@ "strings" "t73f.de/r/zsc/api" "t73f.de/r/zsc/attrs" "zettelstore.de/z/ast" - "zettelstore.de/z/config" - "zettelstore.de/z/encoding/atom" - "zettelstore.de/z/encoding/rss" "zettelstore.de/z/parser" "zettelstore.de/z/query" "zettelstore.de/z/zettel/meta" ) // QueryAction transforms a list of metadata according to query actions into a AST nested list. -func QueryAction(ctx context.Context, q *query.Query, ml []*meta.Meta, rtConfig config.Config) (ast.BlockNode, int) { +func QueryAction(ctx context.Context, q *query.Query, ml []*meta.Meta) (ast.BlockNode, int) { ap := actionPara{ ctx: ctx, q: q, ml: ml, kind: ast.NestedListUnordered, minVal: -1, maxVal: -1, - title: rtConfig.GetSiteName(), } actions := q.Actions() if len(actions) == 0 { return ap.createBlockNodeMeta("") } acts := make([]string, 0, len(actions)) - for i, act := range actions { + for _, act := range actions { if strings.HasPrefix(act, api.NumberedAction[0:1]) { ap.kind = ast.NestedListOrdered continue } if strings.HasPrefix(act, api.MinAction) { @@ -64,26 +60,18 @@ if num, err := strconv.Atoi(act[3:]); err == nil && num > 0 { ap.maxVal = num continue } } - if act == api.TitleAction && i+1 < len(actions) { - ap.title = strings.Join(actions[i+1:], " ") - break - } if act == api.ReIndexAction { continue } acts = append(acts, act) } var firstUnknowAct string for _, act := range acts { switch act { - case api.AtomAction: - return ap.createBlockNodeAtom(rtConfig) - case api.RSSAction: - return ap.createBlockNodeRSS(rtConfig) case api.KeysAction: return ap.createBlockNodeMetaKeys() } key := strings.ToLower(act) switch meta.Type(key) { @@ -108,11 +96,10 @@ q *query.Query ml []*meta.Meta kind ast.NestedListKind minVal int maxVal int - title string } func (ap *actionPara) createBlockNodeWord(key string) (ast.BlockNode, int) { var buf bytes.Buffer ccs, bufLen := ap.prepareCatAction(key, &buf) @@ -348,31 +335,5 @@ } return result } func calcBudget(total, curSize float64) float64 { return math.Round(total / (fontSizes64 - curSize)) } - -func (ap *actionPara) createBlockNodeRSS(cfg config.Config) (ast.BlockNode, int) { - var rssConfig rss.Configuration - rssConfig.Setup(ap.ctx, cfg) - rssConfig.Title = ap.title - data := rssConfig.Marshal(ap.q, ap.ml) - - return &ast.VerbatimNode{ - Kind: ast.VerbatimProg, - Attrs: attrs.Attributes{"lang": "xml"}, - Content: data, - }, len(ap.ml) -} - -func (ap *actionPara) createBlockNodeAtom(cfg config.Config) (ast.BlockNode, int) { - var atomConfig atom.Configuration - atomConfig.Setup(cfg) - atomConfig.Title = ap.title - data := atomConfig.Marshal(ap.q, ap.ml) - - return &ast.VerbatimNode{ - Kind: ast.VerbatimProg, - Attrs: attrs.Attributes{"lang": "xml"}, - Content: data, - }, len(ap.ml) -} Index: go.mod ================================================================== --- go.mod +++ go.mod @@ -8,11 +8,11 @@ golang.org/x/crypto v0.31.0 golang.org/x/term v0.27.0 golang.org/x/text v0.21.0 t73f.de/r/sx v0.0.0-20240814083626-4df0ec6454b5 t73f.de/r/sxwebs v0.0.0-20241031144449-53c3b2ed1a6f - t73f.de/r/zsc v0.0.0-20241213121052-fd15ae683e82 + t73f.de/r/zsc v0.0.0-20241213141447-7902e0d34990 ) require ( golang.org/x/sys v0.28.0 // indirect t73f.de/r/webs v0.0.0-20241031141359-cd4f76a622cd // indirect Index: go.sum ================================================================== --- go.sum +++ go.sum @@ -14,7 +14,7 @@ t73f.de/r/sx v0.0.0-20240814083626-4df0ec6454b5/go.mod h1:VRvsWoBErPKvMieDMMk1hsh1tb9sA4ijEQWGw/TbtQ0= t73f.de/r/sxwebs v0.0.0-20241031144449-53c3b2ed1a6f h1:VJ4S7YWy9tCJuFz5MckqUjjktPaf0kpnTkNBVRVXpo4= t73f.de/r/sxwebs v0.0.0-20241031144449-53c3b2ed1a6f/go.mod h1:IaM+U+LvYTYeuiIS5cwZW6kcEpdwoKBYVCU7LZr4Sgk= t73f.de/r/webs v0.0.0-20241031141359-cd4f76a622cd h1:+7cqJonXKDso+uPvsvOPl7BiLkhj8VQT/Has8qC5VIQ= t73f.de/r/webs v0.0.0-20241031141359-cd4f76a622cd/go.mod h1:NSoOON8be62MfQZzlCApK27Jt2zhIa6Vrmo9RJ4tOnQ= -t73f.de/r/zsc v0.0.0-20241213121052-fd15ae683e82 h1:Bl3iCW9bHx9CeIyWUMLi9xqRV7mHh/1HS6rBnt5QQQU= -t73f.de/r/zsc v0.0.0-20241213121052-fd15ae683e82/go.mod h1:sQWKzNp0I18aSFnKJjAyhL1zTWITIj1v2acWv4GvuIY= +t73f.de/r/zsc v0.0.0-20241213141447-7902e0d34990 h1:iUDHrc4tjfq3UZT3HLrqx2HMN4fZpFCdpNqgr73vTOw= +t73f.de/r/zsc v0.0.0-20241213141447-7902e0d34990/go.mod h1:sQWKzNp0I18aSFnKJjAyhL1zTWITIj1v2acWv4GvuIY= Index: query/query.go ================================================================== --- query/query.go +++ query/query.go @@ -334,11 +334,11 @@ } if len(q.zids) > 0 { return true } if len(q.actions) > 0 { - // Unknown, what an action will use. Example: RSS needs api.KeyPublished. + // Unknown, what an action may use. For examples: KEYS action uses all metadata. return true } for _, term := range q.terms { for key := range term.keys { if meta.IsProperty(key) { Index: web/adapter/webui/create_zettel.go ================================================================== --- web/adapter/webui/create_zettel.go +++ web/adapter/webui/create_zettel.go @@ -107,11 +107,11 @@ sb.WriteString(p.Key) sb.WriteString(": ") sb.WriteString(p.Value) sb.WriteByte('\n') } - env, rb := wui.createRenderEnv(ctx, "form", wui.rtConfig.Get(ctx, nil, api.KeyLang), title, user) + env, rb := wui.createRenderEnv(ctx, "form", wui.getUserLang(ctx), title, user) rb.bindString("heading", sx.MakeString(title)) rb.bindString("form-action-url", sx.MakeString(formActionURL)) rb.bindString("role-data", makeStringList(roleData)) rb.bindString("syntax-data", makeStringList(syntaxData)) rb.bindString("meta", sx.MakeString(sb.String())) @@ -171,11 +171,11 @@ metaSeq, err := queryMeta.Run(box.NoEnrichQuery(ctx, q), q) if err != nil { wui.reportError(ctx, w, err) return } - entries, _ := evaluator.QueryAction(ctx, q, metaSeq, wui.rtConfig) + entries, _ := evaluator.QueryAction(ctx, q, metaSeq) bns := evaluate.RunBlockNode(ctx, entries) enc := zmkenc.Create() var zmkContent bytes.Buffer _, err = enc.WriteBlocks(&zmkContent, &bns) if err != nil { Index: web/adapter/webui/delete_zettel.go ================================================================== --- web/adapter/webui/delete_zettel.go +++ web/adapter/webui/delete_zettel.go @@ -49,12 +49,11 @@ } m := zs[0].Meta user := server.GetUser(ctx) env, rb := wui.createRenderEnv( - ctx, "delete", - wui.rtConfig.Get(ctx, nil, api.KeyLang), "Delete Zettel "+m.Zid.String(), user) + ctx, "delete", wui.getUserLang(ctx), "Delete Zettel "+m.Zid.String(), user) if len(zs) > 1 { rb.bindString("shadowed-box", sx.MakeString(zs[1].Meta.GetDefault(api.KeyBoxNumber, "???"))) rb.bindString("incoming", nil) } else { rb.bindString("shadowed-box", nil) Index: web/adapter/webui/get_info.go ================================================================== --- web/adapter/webui/get_info.go +++ web/adapter/webui/get_info.go @@ -57,11 +57,11 @@ if err != nil { wui.reportError(ctx, w, err) return } - enc := wui.getSimpleHTMLEncoder(wui.rtConfig.Get(ctx, zn.InhMeta, api.KeyLang)) + enc := wui.getSimpleHTMLEncoder(wui.getConfig(ctx, zn.InhMeta, api.KeyLang)) getTextTitle := wui.makeGetTextTitle(ctx, ucGetZettel) evalMeta := func(val string) ast.InlineSlice { return ucEvaluate.RunMetadata(ctx, val) } pairs := zn.Meta.ComputedPairs() @@ -84,11 +84,11 @@ if err != nil { wui.reportError(ctx, w, err) return } - entries, _ := evaluator.QueryAction(ctx, nil, unlinkedMeta, wui.rtConfig) + entries, _ := evaluator.QueryAction(ctx, nil, unlinkedMeta) bns := ucEvaluate.RunBlockNode(ctx, entries) unlinkedContent, _, err := enc.BlocksSxn(&bns) if err != nil { wui.reportError(ctx, w, err) return @@ -95,11 +95,11 @@ } encTexts := encodingTexts() shadowLinks := getShadowLinks(ctx, zid, ucGetAllZettel) user := server.GetUser(ctx) - env, rb := wui.createRenderEnv(ctx, "info", wui.rtConfig.Get(ctx, nil, api.KeyLang), title, user) + env, rb := wui.createRenderEnv(ctx, "info", wui.getUserLang(ctx), title, user) rb.bindString("metadata", metadata) rb.bindString("local-links", locLinks) rb.bindString("query-links", queryLinks) rb.bindString("ext-links", extLinks) rb.bindString("unlinked-content", unlinkedContent) Index: web/adapter/webui/get_zettel.go ================================================================== --- web/adapter/webui/get_zettel.go +++ web/adapter/webui/get_zettel.go @@ -49,11 +49,12 @@ if err != nil { wui.reportError(ctx, w, err) return } - enc := wui.getSimpleHTMLEncoder(wui.rtConfig.Get(ctx, zn.InhMeta, api.KeyLang)) + zettelLang := wui.getConfig(ctx, zn.InhMeta, api.KeyLang) + enc := wui.getSimpleHTMLEncoder(zettelLang) metaObj := enc.MetaSxn(zn.InhMeta, createEvalMetadataFunc(ctx, evaluate)) content, endnotes, err := enc.BlocksSxn(&zn.Ast) if err != nil { wui.reportError(ctx, w, err) return @@ -61,11 +62,11 @@ user := server.GetUser(ctx) getTextTitle := wui.makeGetTextTitle(ctx, getZettel) title := parser.NormalizedSpacedText(zn.InhMeta.GetTitle()) - env, rb := wui.createRenderEnv(ctx, "zettel", wui.rtConfig.Get(ctx, zn.InhMeta, api.KeyLang), title, user) + env, rb := wui.createRenderEnv(ctx, "zettel", zettelLang, title, user) rb.bindSymbol(symMetaHeader, metaObj) rb.bindString("heading", sx.MakeString(title)) if role, found := zn.InhMeta.Get(api.KeyRole); found && role != "" { rb.bindString("role-url", sx.MakeString(wui.NewURLBuilder('h').AppendQuery(api.KeyRole+api.SearchOperatorHas+role).String())) } @@ -120,11 +121,11 @@ } func (wui *WebUI) bindLinks(ctx context.Context, rb *renderBinder, varPrefix string, m *meta.Meta, key, configKey string, getTextTitle getTextTitleFunc) { varLinks := varPrefix + "-links" var symOpen *sx.Symbol - switch wui.rtConfig.Get(ctx, m, configKey) { + switch wui.getConfig(ctx, m, configKey) { case "false": rb.bindString(varLinks, sx.Nil()) return case "close": default: Index: web/adapter/webui/home.go ================================================================== --- web/adapter/webui/home.go +++ web/adapter/webui/home.go @@ -36,11 +36,11 @@ ctx := r.Context() if p := r.URL.Path; p != "/" { wui.reportError(ctx, w, adapter.ErrResourceNotFound{Path: p}) return } - homeZid, _ := id.Parse(wui.rtConfig.Get(ctx, nil, config.KeyHomeZettel)) + homeZid, _ := id.Parse(wui.getConfig(ctx, nil, config.KeyHomeZettel)) apiHomeZid := homeZid.ZettelID() if homeZid != id.DefaultHomeZid { if _, err := s.GetZettel(ctx, homeZid); err == nil { wui.redirectFound(w, r, wui.NewURLBuilder('h').SetZid(apiHomeZid)) return Index: web/adapter/webui/lists.go ================================================================== --- web/adapter/webui/lists.go +++ web/adapter/webui/lists.go @@ -13,11 +13,10 @@ package webui import ( "context" - "io" "net/http" "net/url" "slices" "strconv" "strings" @@ -25,15 +24,11 @@ "t73f.de/r/sx" "t73f.de/r/sxwebs/sxhtml" "t73f.de/r/zsc/api" "t73f.de/r/zsc/shtml" "zettelstore.de/z/ast" - "zettelstore.de/z/encoding/atom" - "zettelstore.de/z/encoding/rss" - "zettelstore.de/z/encoding/xml" "zettelstore.de/z/evaluator" - "zettelstore.de/z/query" "zettelstore.de/z/usecase" "zettelstore.de/z/web/adapter" "zettelstore.de/z/web/server" "zettelstore.de/z/zettel/id" "zettelstore.de/z/zettel/meta" @@ -62,49 +57,39 @@ actions, err := adapter.TryReIndex(ctx, q.Actions(), metaSeq, reIndex) if err != nil { wui.reportError(ctx, w, err) return } - if len(actions) > 0 { - if len(metaSeq) > 0 { - for _, act := range actions { - if act == api.RedirectAction { - ub := wui.NewURLBuilder('h').SetZid(metaSeq[0].Zid.ZettelID()) - wui.redirectFound(w, r, ub) - return - } - } - } - switch actions[0] { - case api.AtomAction: - wui.renderAtom(w, q, metaSeq) - return - case api.RSSAction: - wui.renderRSS(ctx, w, q, metaSeq) - return - } - } + if len(actions) > 0 && len(metaSeq) > 0 { + for _, act := range actions { + if act == api.RedirectAction { + ub := wui.NewURLBuilder('h').SetZid(metaSeq[0].Zid.ZettelID()) + wui.redirectFound(w, r, ub) + return + } + } + } + + userLang := wui.getUserLang(ctx) var content, endnotes *sx.Pair numEntries := 0 - if bn, cnt := evaluator.QueryAction(ctx, q, metaSeq, wui.rtConfig); bn != nil { - enc := wui.getSimpleHTMLEncoder(wui.rtConfig.Get(ctx, nil, api.KeyLang)) + if bn, cnt := evaluator.QueryAction(ctx, q, metaSeq); bn != nil { + enc := wui.getSimpleHTMLEncoder(userLang) content, endnotes, err = enc.BlocksSxn(&ast.BlockSlice{bn}) if err != nil { wui.reportError(ctx, w, err) return } numEntries = cnt } + siteName := wui.rtConfig.GetSiteName() user := server.GetUser(ctx) - env, rb := wui.createRenderEnv( - ctx, "list", - wui.rtConfig.Get(ctx, nil, api.KeyLang), - wui.rtConfig.GetSiteName(), user) + env, rb := wui.createRenderEnv(ctx, "list", userLang, siteName, user) if q == nil { - rb.bindString("heading", sx.MakeString(wui.rtConfig.GetSiteName())) + rb.bindString("heading", sx.MakeString(siteName)) } else { var sb strings.Builder q.PrintHuman(&sb) rb.bindString("heading", sx.MakeString(sb.String())) } @@ -199,48 +184,10 @@ sxZtl = sxZtl.Cons(sx.MakeString(", ")) } return sxZtl.Cons(link) } -func (wui *WebUI) renderRSS(ctx context.Context, w http.ResponseWriter, q *query.Query, ml []*meta.Meta) { - var rssConfig rss.Configuration - rssConfig.Setup(ctx, wui.rtConfig) - if actions := q.Actions(); len(actions) > 2 && actions[1] == api.TitleAction { - rssConfig.Title = strings.Join(actions[2:], " ") - } - data := rssConfig.Marshal(q, ml) - - adapter.PrepareHeader(w, rss.ContentType) - w.WriteHeader(http.StatusOK) - var err error - if _, err = io.WriteString(w, xml.Header); err == nil { - _, err = w.Write(data) - } - if err != nil { - wui.log.Error().Err(err).Msg("unable to write RSS data") - } -} - -func (wui *WebUI) renderAtom(w http.ResponseWriter, q *query.Query, ml []*meta.Meta) { - var atomConfig atom.Configuration - atomConfig.Setup(wui.rtConfig) - if actions := q.Actions(); len(actions) > 2 && actions[1] == api.TitleAction { - atomConfig.Title = strings.Join(actions[2:], " ") - } - data := atomConfig.Marshal(q, ml) - - adapter.PrepareHeader(w, atom.ContentType) - w.WriteHeader(http.StatusOK) - var err error - if _, err = io.WriteString(w, xml.Header); err == nil { - _, err = w.Write(data) - } - if err != nil { - wui.log.Error().Err(err).Msg("unable to write Atom data") - } -} - func (wui *WebUI) handleTagZettel(w http.ResponseWriter, r *http.Request, tagZettel *usecase.TagZettel, vals url.Values) bool { tag := vals.Get(api.QueryKeyTag) if tag == "" { return false } Index: web/adapter/webui/login.go ================================================================== --- web/adapter/webui/login.go +++ web/adapter/webui/login.go @@ -16,11 +16,10 @@ import ( "context" "net/http" "t73f.de/r/sx" - "t73f.de/r/zsc/api" "zettelstore.de/z/auth" "zettelstore.de/z/usecase" "zettelstore.de/z/web/adapter" "zettelstore.de/z/zettel/id" ) @@ -38,11 +37,11 @@ wui.renderLoginForm(wui.clearToken(r.Context(), w), w, false) }) } func (wui *WebUI) renderLoginForm(ctx context.Context, w http.ResponseWriter, retry bool) { - env, rb := wui.createRenderEnv(ctx, "login", wui.rtConfig.Get(ctx, nil, api.KeyLang), "Login", nil) + env, rb := wui.createRenderEnv(ctx, "login", wui.getUserLang(ctx), "Login", nil) rb.bindString("retry", sx.MakeBoolean(retry)) if rb.err == nil { rb.err = wui.renderSxnTemplate(ctx, w, id.LoginTemplateZid, env) } if err := rb.err; err != nil { Index: web/adapter/webui/template.go ================================================================== --- web/adapter/webui/template.go +++ web/adapter/webui/template.go @@ -314,13 +314,13 @@ lst = lst.Cons(sx.Cons(text, link)) } return lst } func (wui *WebUI) calculateFooterSxn(ctx context.Context) *sx.Pair { - if footerZid, err := id.Parse(wui.rtConfig.Get(ctx, nil, config.KeyFooterZettel)); err == nil { + if footerZid, err := id.Parse(wui.getConfig(ctx, nil, config.KeyFooterZettel)); err == nil { if zn, err2 := wui.evalZettel.Run(ctx, footerZid, ""); err2 == nil { - htmlEnc := wui.getSimpleHTMLEncoder(wui.rtConfig.Get(ctx, zn.InhMeta, api.KeyLang)).SetUnique("footer-") + htmlEnc := wui.getSimpleHTMLEncoder(wui.getConfig(ctx, zn.InhMeta, api.KeyLang)).SetUnique("footer-") if content, endnotes, err3 := htmlEnc.BlocksSxn(&zn.Ast); err3 == nil { if content != nil && endnotes != nil { content.LastPair().SetCdr(sx.Cons(endnotes, nil)) } return content Index: web/adapter/webui/webui.go ================================================================== --- web/adapter/webui/webui.go +++ web/adapter/webui/webui.go @@ -124,10 +124,17 @@ wui.rootBinding = wui.createRenderBinding() wui.observe(box.UpdateInfo{Box: mgr, Reason: box.OnReload, Zid: id.Invalid}) mgr.RegisterObserver(wui.observe) return wui } + +func (wui *WebUI) getConfig(ctx context.Context, m *meta.Meta, key string) string { + return wui.rtConfig.Get(ctx, m, key) +} +func (wui *WebUI) getUserLang(ctx context.Context) string { + return wui.getConfig(ctx, nil, api.KeyLang) +} var ( symDetail = sx.MakeSymbol("DETAIL") symMetaHeader = sx.MakeSymbol("META-HEADER") ) Index: www/changes.wiki ================================================================== --- www/changes.wiki +++ www/changes.wiki @@ -1,9 +1,13 @@ Change Log

Changes for Version 0.20.0 (pending)

+ * Query aggregates ATOM and RSS are removed, as + well as the accompanying TITLE query action (parameter). + Were announced as deprecated in version 0.19. + (major)

Changes for Version 0.19.0 (2024-12-13)

* Remove support for renaming zettel, i.e. changing zettel identifier. Was announced as deprecated in version 0.18.