|
⍝ |Cheat sheet: | #.MarkAPL.Help 0 |
⍝ |Reference: | #.MarkAPL.Reference 0 |
⍝ Kai Jaeger
@@ -59,11 +59,20 @@
∇ r←Version
:Access Public Shared
⍝ See `History`
- r←'MarkAPL' '11.0.4+246' '2022-10-26'
+ r←'MarkAPL' '11.1.0+246' '2022-08-13'
∇
∇ History
:Access Public Shared
+ ⍝ * 11.1.0 ⋄ 2023-08-13
+ ⍝ * Layout `MarkAPL_screen` improved (TOC and inline code)
+ ⍝ * Layout `BlackOnWhite_screen` improved (TOC and inline code)
+ ⍝ * Documentation improved / updated
+ ⍝ * `LICENSE` updated
+ ⍝ * Packages updated
+ ⍝ * `Make` updated
+ ⍝ * 11.0.5 ⋄ 2022-06-15
+ ⍝ * Bug fix: `Matrix2MarkdownList` complained wrongly that ⍵ should have 2 columns: 3 is correct
⍝ * 11.0.4 ⋄ 2022-10-26
⍝ * Bug fixes
⍝ * `ShowHtml` did not cope when the right argument pointed to the current directory
@@ -523,9 +532,9 @@
⍝ 2. Nesting level. May start with either 0 or 1.
⍝ 3. Text vector of vector of text vector.
'Invalid right argument - not a matrix'⎕SIGNAL 11/⍨2≠⍴⍴mat
- 'Invalid right argument - must have 2 columns'⎕SIGNAL 11/⍨3≠2⊃⍴mat
+ 'Invalid right argument - must have 3 columns'⎕SIGNAL 11/⍨3≠2⊃⍴mat
'First line''s level must be either 0 or 1'⎕SIGNAL 11/⍨~(⊃mat)∊0 1
- 'Invalid right argument - must have 2 columns'⎕SIGNAL 11/⍨~∧/mat[;1]∊0,⍳999
+ 'Invalid right argument - must have 3 columns'⎕SIGNAL 11/⍨~∧/mat[;1]∊0,⍳999
mat[;2]←{⍵-1}⍣(1=⊃mat[;2])⊣mat[;2] ⍝ Ensure 0 is first level
md←mat[;2]⍴¨' '
type←0=mat[;1]
diff --git a/APLSource/Registry/GetGroupData.aplf b/APLSource/Registry/GetGroupData.aplf
index b3d963dd0..5fa02c4c4 100644
--- a/APLSource/Registry/GetGroupData.aplf
+++ b/APLSource/Registry/GetGroupData.aplf
@@ -1,4 +1,4 @@
- r←{what}GetGroupData(path groupName);dcfFilename;dcfTie;markdown;email;folder
+ r←{what}GetGroupData(path groupName);dcfFilename;dcfTie;markdown;email;folder;cred;ind
⍝ Returns the data saved for a group as a matrix:
⍝ [;1] The name
⍝ [;2] The corresponding data\\
@@ -16,6 +16,12 @@
dcfTie←dcfFilename ⎕FSTIE 0
markdown←⎕FREAD dcfTie 3
email←⎕FREAD dcfTie 4
+ :If 0=≢email
+ cred←##.Server.ReadCredentialFile ##.Server.G.RegistryPath,'/Credentials.csv'
+ ind←cred[;1]⍳⊂groupName
+ :AndIf ind≤≢cred
+ email←4⊃cred[ind;],'' '' ⍝ Paranoia because of format change in 2023-11
+ :EndIf
r←2 2⍴'markdown'markdown'email'email
⎕FUNTIE dcfTie
:If 0<⎕NC'what'
diff --git a/APLSource/Registry/History.apla b/APLSource/Registry/History.apla
index e448175ea..7d11f6501 100644
--- a/APLSource/Registry/History.apla
+++ b/APLSource/Registry/History.apla
@@ -1,4 +1,14 @@
(
+ '* 0.103.0 ⋄ 2023-11-03'
+ ' * You must specify now an email address for your group before you can publish a package '
+ ' * Bug fixes'
+ ' * `BuildPackages` checks whether the .NET Framework is available and throws an error if not'
+ ' * `ListVersions` works on local un-managed Registries'
+ ' * `UpdateTatin` did not define its explicit result in case of success, causing a VALUE ERROR'
+ ' * Documentation for how to add a new API key was flawed.'
+ ' * `GetRegistryIndex` did not return anything useful in case of a local but unmanaged Registry'
+ '* 0.102.3 ⋄ 2023-10-13'
+ ' * Bug fix regarding the `files` property: if that pointed to a file in a sub-folder it was not handled correctly'
'* 0.102.2 ⋄ 2023-10-09'
' * Documentation corrected regarding installation'
'* 0.102.1 ⋄ 2023-10-07'
diff --git a/APLSource/Registry/Index/GetRegistryIndex.aplf b/APLSource/Registry/Index/GetRegistryIndex.aplf
index 1c01bbdef..e55ba91a9 100644
--- a/APLSource/Registry/Index/GetRegistryIndex.aplf
+++ b/APLSource/Registry/Index/GetRegistryIndex.aplf
@@ -1,6 +1,6 @@
r←{nested}GetRegistryIndex path;filename;list
⍝ In a managed Tatin Registry there must be a file "tatin_index.txt".
-⍝ In a local un-managed Registry there is none, so we list all directories
+⍝ In a local un-managed Registry there is none.
⍝ By default a simple character vector (⎕UCS 10-separated) is returned.
⍝ You may change this by specifying a 1 as `⍺`.
nested←{0<⎕NC ⍵:⍎⍵ ⋄ 0}'nested'
@@ -8,5 +8,6 @@
:If 0<##.F.IsFile filename
r←⊃##.F.NGET filename nested
:Else
- r←(1+≢path)↓¨##.F.ListDirs path
+ r←(1+≢path)↓¨##.F.ListDirs path ⍝ It's a local Registry, and it is not managed, se we go for directories
:EndIf
+⍝Done
diff --git a/APLSource/Registry/Version.aplf b/APLSource/Registry/Version.aplf
index 3c5e9e585..b50a31aa3 100644
--- a/APLSource/Registry/Version.aplf
+++ b/APLSource/Registry/Version.aplf
@@ -1,3 +1,3 @@
r←Version
⍝ See also `History`
- r←'Tatin' '0.102.2+1680' '2023-10-09'
+ r←'Tatin' '0.103.0+1702' '2023-11-07'
diff --git a/APLSource/Server/AcceptCredential.aplf b/APLSource/Server/AcceptCredential.aplf
index f1fa8d337..7d0e98f38 100644
--- a/APLSource/Server/AcceptCredential.aplf
+++ b/APLSource/Server/AcceptCredential.aplf
@@ -1,9 +1,11 @@
- okayFlag←credentials AcceptCredential(apiKey groupName);credentials;ind;salt;hash;apiKeys;groupNames
+ okayFlag←credentials AcceptCredential(apiKey groupName);credentials;ind;salt;hash;apiKeys;groupNames
⍝ Takes an API key and a group name and checks whether that is found in the array `credentials`.
⍝ Note that `G.Credentials` is usually provided as `⍺` except test cases etc.\\
⍝ This function is called when the user attempts to perform a PUT (read: "Publish") or
⍝ a DELETE (if ever) or any other operation that requires authentication.\\
⍝ apiKey must be clear text.
+⍝ Note that with version this function also checks whether for a group name that is not * and
+⍝ requires an API key there is an email address defined.
okayFlag←1
:If 0<≢credentials ⍝ Do we have any credentials saved at all?
:If 2=⍴⍴credentials
diff --git a/APLSource/Server/ConvertCredentials.aplf b/APLSource/Server/ConvertCredentials.aplf
index 0ddd5064c..47343e940 100644
--- a/APLSource/Server/ConvertCredentials.aplf
+++ b/APLSource/Server/ConvertCredentials.aplf
@@ -1,10 +1,9 @@
-credentials←credentials ConvertCredentials newCredentials;i;group;apiKey;salt;hash
+ credentials←credentials ConvertCredentials newCredentials;i;group;apiKey;salt;hash
⍝ Converts API-keys in `newCredentials` into hashes and adds a Salt along the way.
⍝ Eventually merges `credentials` and `newCredentials`.
:If 0<≢newCredentials
- newCredentials,←⊂''
:For i :In ⍳≢newCredentials
- (group apiKey)←2↑' '~⍨¨newCredentials[i;]
+ (group apiKey salt)←3↑' '~⍨¨newCredentials[i;]
:If 0=≢apiKey
newCredentials[i;]←group'' ''
:Else
diff --git a/APLSource/Server/EditGroupHomepage_.aplf b/APLSource/Server/EditGroupHomepage_.aplf
index 43b48fba1..50e0a5038 100644
--- a/APLSource/Server/EditGroupHomepage_.aplf
+++ b/APLSource/Server/EditGroupHomepage_.aplf
@@ -13,7 +13,7 @@
html,←⊂H.BR
html,←⊂H.BR
- html,←⊂'email'H.Label'Email address:'
+ html,←⊂'email'H.Label'Single email address:'
html,←⊂H.BR
parms←⎕NS''
parms.(id name type placeholder value)←'email' 'email' 'email' 'your.name@email.address'email
@@ -32,7 +32,7 @@
html,←⊂H.Input parms
html,←⊂H.BR
- ⍝ This is used to tell the server what this is all about. that allows the server to determine that
+ ⍝ This is used to tell the server what this is all about. That allows the server to determine that
⍝ the content must be massaged in a specific way.
parms←⎕NS''
parms.(id name type value style readonly)←'sgh' 'sgh' 'text' 'save-group-homepage' 'display:none;' 'readonly'
diff --git a/APLSource/Server/Handle_PUT_And_POST.aplf b/APLSource/Server/Handle_PUT_And_POST.aplf
index 5f1676d27..c0ae18d6f 100644
--- a/APLSource/Server/Handle_PUT_And_POST.aplf
+++ b/APLSource/Server/Handle_PUT_And_POST.aplf
@@ -10,13 +10,18 @@
groupName←request R.GetQueryParameter'group'
:EndIf
:If G.Credentials AcceptCredential apiKey groupName
- :If Reg.IsValidPackageID_Complete request.RequestTarget
- response←SavePackage request
- :ElseIf request IsREST_v1 request.RequestTarget
- response←request Handle_PUT_And_POST_REST_Version1 request.RequestTarget
+ :If 0=≢'email'Reg.GetGroupData G.RegistryPath groupName
+ :AndIf 0 G.INI.Get 'CONFIG:EnforceEmailAddress'
+ response←request RespondWithHTML 400 'No email address defined' 'You cannot publish without defining an email address for your group.'
:Else
- response←request Respond 400 ⍝ 400 ←→ Bad Request
- response.Content←'Neither valid package ID nor proper REST request'
+ :If Reg.IsValidPackageID_Complete request.RequestTarget
+ response←SavePackage request
+ :ElseIf request IsREST_v1 request.RequestTarget
+ response←request Handle_PUT_And_POST_REST_Version1 request.RequestTarget
+ :Else
+ response←request Respond 400 ⍝ 400 ←→ Bad Request
+ response.Content←'Neither valid package ID nor proper REST request'
+ :EndIf
:EndIf
:Else
response←request RespondWithHTML 401 'Unauthorized request' ⍝ 401 ←→ Unauthorized
diff --git a/APLSource/Server/OnRequest.aplf b/APLSource/Server/OnRequest.aplf
index 9c3f96944..5b6f0523d 100644
--- a/APLSource/Server/OnRequest.aplf
+++ b/APLSource/Server/OnRequest.aplf
@@ -31,7 +31,7 @@
:EndIf
:If 200≠response.StatusCode
⍝ Add potential error message in case something went wrong:
- logMsg,←(326≠⎕DR response.Content)/'; ',response.Content
+ logMsg,←((~∨/''⍷∊response.Content)∧326≠⎕DR response.Content)/'; ',response.Content
:EndIf
:EndIf
P.AppLog logMsg
diff --git a/APLSource/Server/ProcessCredentials.aplf b/APLSource/Server/ProcessCredentials.aplf
index 8f8409f30..3b8d444bf 100644
--- a/APLSource/Server/ProcessCredentials.aplf
+++ b/APLSource/Server/ProcessCredentials.aplf
@@ -1,7 +1,6 @@
- G←ProcessCredentials G;filename;credentials;body;oldFilename;newCredentials
+ G←ProcessCredentials G;filename;credentials;body;newCredentialsFilename;newCredentials
⍝ Returns a matrix with {group} - Salt - API-key-hash combinations used for authentication.
-⍝ For the time being, if the file is still lacking an email address, no conversion is done.
- oldFilename←G.RegistryPath,'/Credentials.txt'
+ newCredentialsFilename←G.RegistryPath,'/Credentials.txt'
filename←G.RegistryPath,'/Credentials.csv'
:If 0=F.Exists filename
''F.NPUT filename
@@ -13,10 +12,10 @@
:Else
G.Credentials←credentials
:EndIf
- :If 0<≢newCredentials←ReadCredentialFile oldFilename
+ :If 0<≢newCredentials←ReadCredentialFile newCredentialsFilename
G.Credentials←G.Credentials ConvertCredentials newCredentials
(⊂⊃¨{⍺,',',⍵}/¨↓G.Credentials)F.NPUT filename 1
- F.DeleteFile oldFilename
+ F.DeleteFile newCredentialsFilename
:EndIf
G.CredentialsTimestamp←Reg.Timestamp2Float⊃⊃('type' 3)F.Dir filename
⍝Done
diff --git a/APLSource/Server/ReadCredentialFile.aplf b/APLSource/Server/ReadCredentialFile.aplf
index 75a6e9fe2..c2133480d 100644
--- a/APLSource/Server/ReadCredentialFile.aplf
+++ b/APLSource/Server/ReadCredentialFile.aplf
@@ -1,11 +1,15 @@
r←ReadCredentialFile filename;buff
⍝ Read the credential file (either Credentials.txt or Credentials.csv), and remove any comments
-⍝ as well as empty lines.
- r←0 2⍴⊂''
+⍝ (= lines that start with a semicolon) as well as empty lines.
+⍝ Returns a matrix with 4 columns:
+⍝ [1] Group name
+⍝ [2] API key
+⍝ [3] SALT (empty in case of Credentials.txt)
+ r←0 4⍴⊂''
:If F.IsFile filename
:AndIf 0<≢buff←⊃F.NGET filename 1
:AndIf 0<≢buff←(';'≠⊃¨buff)/buff
:AndIf 0<≢buff←(0<≢¨buff)/buff
buff←{','@(⍸'='=⍵)⊣⍵}¨buff ⍝ Exchange the deprecated "=" against ","
- r←↑','A.Split¨buff
+ r←3↑⍤1⊢(↑','A.Split¨buff),⊂''
:EndIf
diff --git a/APLSource/Server/RespondWithHTML.aplf b/APLSource/Server/RespondWithHTML.aplf
index 0879a5ee2..5d4fadb5a 100644
--- a/APLSource/Server/RespondWithHTML.aplf
+++ b/APLSource/Server/RespondWithHTML.aplf
@@ -1,13 +1,17 @@
- response←request RespondWithHTML y;html;msg;statusCode
-⍝ Compiles an HTML response with "msg" becoming an tag
- (statusCode msg)←2↑(⊆y),'' ''
- :If 0=≢msg
- msg←GetReasonPhraseFor statusCode
+ response←request RespondWithHTML y;html;msg;statusCode;caption
+⍝ Compiles an HTML response with "caption" becoming an tag and
+⍝ the (optional) "msg" one to many
tags.
+ (statusCode caption msg)←3↑(⊆y),'' '' ''
+ :If 0=≢caption
+ caption←GetReasonPhraseFor statusCode
:EndIf
response←request Respond statusCode
html←HtmlHeader''
- html,←⊂'
',msg,' (',(⍕statusCode),')
'
+ html,←⊂'',caption,' (',(⍕statusCode),')
'
html,←AddSpecialMessage ⍬
+ :If 0<≢msg
+ html,←{'',⍵,'
'}¨⊆msg
+ :EndIf
html,←'