Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
interkit
interkit-experiments
Commits
5d6467d7
Commit
5d6467d7
authored
1 month ago
by
Holger H
Browse files
Options
Download
Email Patches
Plain Diff
embed images into projectmeta as data-url
parent
98f2219b
md_images
No related merge requests found
Pipeline
#1665
passed with stages
in 7 minutes and 49 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
app-bundler/src/get_readme.mjs
+23
-22
app-bundler/src/get_readme.mjs
app-bundler/src/projectmeta.mjs
+72
-13
app-bundler/src/projectmeta.mjs
app-bundler/src/updaters/mdFiles.mjs
+8
-7
app-bundler/src/updaters/mdFiles.mjs
svelte-admin/src/Project/ProjectDashboard.svelte
+4
-0
svelte-admin/src/Project/ProjectDashboard.svelte
with
107 additions
and
42 deletions
+107
-42
app-bundler/src/get_readme.mjs
+
23
-
22
View file @
5d6467d7
...
...
@@ -2,7 +2,6 @@ import * as path from 'path'
import
{
promises
as
fs
}
from
'
fs
'
import
{
existsSync
}
from
'
fs
'
import
{
resolveProjectPath
}
from
'
./utils.mjs
'
import
{
processMarkdown
}
from
'
./projectmeta.mjs
'
const
REPOSITORIES_PATH
=
process
.
env
.
REPOSITORIES_PATH
...
...
@@ -18,39 +17,41 @@ export const get_readme = async (req, res) => {
return
}
let
filename
=
false
const
projectPath
=
path
.
join
(
REPOSITORIES_PATH
,
'
projects
'
,
projectId
)
names
.
forEach
(
name
=>
{
extensions
.
forEach
(
extension
=>
{
const
tryPath
=
path
.
join
(
REPOSITORIES_PATH
,
'
projects
'
,
projectId
,
name
+
'
.
'
+
extension
)
console
.
log
(
'
get_readme, trying
'
,
name
+
'
.
'
+
extension
,
)
const
tryPath
=
path
.
join
(
projectPath
,
name
+
'
.
'
+
extension
)
//
console.log('get_readme, trying', name + '.' + extension)
if
(
existsSync
(
tryPath
))
{
filename
=
tryPath
return
}
})
})
if
(
!
filename
)
{
res
.
status
(
404
)
res
.
send
(
'
readme not found
'
)
return
}
fs
.
readFile
(
filename
)
.
then
(
file
=>
file
.
toString
())
.
then
(
async
str
=>
{
const
html
=
await
processMarkdown
(
str
)
if
(
html
)
{
res
.
status
(
200
)
res
.
contentType
(
'
text/html
'
)
res
.
send
(
html
)
return
}
else
{
res
.
status
(
500
)
res
.
send
(
'
error processing markdown
'
)
}
})
.
catch
(
e
=>
{
console
.
error
(
'
get_readme error
'
,
e
)
res
.
status
(
500
)
res
.
send
(
'
error reading readme file
'
)
try
{
const
mdStr
=
await
fs
.
readFile
(
filename
,
'
utf8
'
)
const
html
=
await
processMarkdown
(
mdStr
,
path
.
dirname
(
filename
))
if
(
html
)
{
res
.
status
(
200
)
res
.
contentType
(
'
text/html
'
)
res
.
send
(
html
)
return
})
}
else
{
res
.
status
(
500
)
res
.
send
(
'
error processing markdown
'
)
}
}
catch
(
err
)
{
console
.
error
(
'
get_readme error
'
,
err
)
res
.
status
(
500
)
res
.
send
(
'
error reading readme file
'
)
return
}
}
This diff is collapsed.
Click to expand it.
app-bundler/src/projectmeta.mjs
+
72
-
13
View file @
5d6467d7
import
remark
from
'
remark
'
import
remarkHtml
from
'
remark-html
'
import
{
promises
as
fs
}
from
'
fs
'
import
path
from
'
path
'
import
{
visit
}
from
'
unist-util-visit
'
const
markdownProcessor
=
remark
()
.
use
(
remarkHtml
)
// Check if a path is within the allowed directory
const
isPathWithinDir
=
(
dir
,
filepath
)
=>
{
const
relative
=
path
.
relative
(
dir
,
filepath
)
return
relative
&&
!
relative
.
startsWith
(
'
..
'
)
&&
!
path
.
isAbsolute
(
relative
)
}
export
const
processMarkdown
=
async
str
=>
{
const
ret
=
await
markdownProcessor
.
process
(
str
)
.
then
(
resp
=>
{
let
html
=
resp
.
contents
html
=
html
.
replace
(
/src="
\.?\/?
public
\/
/
,
'
src="
'
)
return
html
})
.
catch
(
e
=>
{
console
.
log
(
'
markdown process error
'
,
e
)
return
false
const
imageToBase64
=
async
(
imagePath
,
basePath
)
=>
{
try
{
// Security check: Only allow images from within the project directory
if
(
!
isPathWithinDir
(
basePath
,
imagePath
))
{
console
.
error
(
'
Security: Attempted to load image from outside project directory:
'
,
imagePath
)
return
null
}
const
imageBuffer
=
await
fs
.
readFile
(
imagePath
)
const
base64
=
imageBuffer
.
toString
(
'
base64
'
)
const
ext
=
path
.
extname
(
imagePath
).
substring
(
1
).
toLowerCase
()
return
`data:image/
${
ext
}
;base64,
${
base64
}
`
}
catch
(
err
)
{
console
.
error
(
'
Error converting image to base64:
'
,
imagePath
,
err
)
return
null
}
}
// Custom remark plugin to handle images
function
remarkEmbedImages
(
basePath
)
{
return
async
function
transformer
(
tree
)
{
const
promises
=
[]
// First collect all image nodes
const
imageNodes
=
[]
visit
(
tree
,
'
image
'
,
(
node
)
=>
{
imageNodes
.
push
(
node
)
})
return
ret
// Then process them all in parallel
await
Promise
.
all
(
imageNodes
.
map
(
async
(
node
)
=>
{
try
{
const
absoluteImagePath
=
path
.
resolve
(
basePath
,
node
.
url
)
const
base64Data
=
await
imageToBase64
(
absoluteImagePath
,
basePath
)
if
(
base64Data
)
{
node
.
url
=
base64Data
}
}
catch
(
err
)
{
console
.
error
(
'
Error processing image:
'
,
err
)
}
}))
}
}
// Create a unified processor that handles both markdown and HTML
const
createProcessor
=
(
basePath
)
=>
{
return
remark
()
.
use
(
remarkEmbedImages
,
basePath
)
.
use
(
remarkHtml
,
{
sanitize
:
false
})
// Allow raw HTML
}
export
const
processMarkdown
=
async
(
str
,
basePath
)
=>
{
try
{
const
processor
=
createProcessor
(
basePath
)
const
file
=
await
processor
.
process
(
str
)
let
html
=
String
(
file
)
// Clean up any remaining relative paths
html
=
html
.
replace
(
/src="
\.?\/?
public
\/
/
,
'
src="
'
)
return
html
}
catch
(
e
)
{
console
.
error
(
'
Markdown process error:
'
,
e
)
return
false
}
}
This diff is collapsed.
Click to expand it.
app-bundler/src/updaters/mdFiles.mjs
+
8
-
7
View file @
5d6467d7
...
...
@@ -6,15 +6,16 @@ import { promises as fs } from "fs";
import
{
processMarkdown
}
from
"
../projectmeta.mjs
"
;
import
interkit_server
from
"
../interkit_server.mjs
"
;
import
{
getProjectPath
}
from
"
../filesystem.mjs
"
;
import
path
from
"
path
"
;
const
watchedFileReMd
=
/^
(
project|readme|description
)\.(
md|markdown
)
$/i
;
const
updateFileMd
=
(
projectId
,
{
path
,
filename
,
basename
,
extension
})
=>
{
//console.log("updateFileMd", { path, filename, basename, extension });
fs
.
readFile
(
p
ath
)
const
updateFileMd
=
(
projectId
,
{
path
:
filePath
,
filename
,
basename
,
extension
})
=>
{
//console.log("updateFileMd", { path
: filePath
, filename, basename, extension });
fs
.
readFile
(
fileP
ath
)
.
then
((
file
)
=>
file
.
toString
())
.
then
(
async
(
mdStr
)
=>
{
const
html
=
await
processMarkdown
(
mdStr
);
const
html
=
await
processMarkdown
(
mdStr
,
path
.
dirname
(
filePath
)
);
interkit_server
.
call
(
"
project.updateUiState
"
,
{
projectId
:
projectId
,
section
:
"
metafile.
"
+
basename
.
toLowerCase
(),
...
...
@@ -27,7 +28,7 @@ const updateFileMd = (projectId, { path, filename, basename, extension }) => {
.
catch
((
e
)
=>
{
console
.
error
(
"
updateFileMd error
"
,
{
path
,
filename
,
basename
,
extension
},
{
path
:
filePath
,
filename
,
basename
,
extension
},
e
);
});
...
...
@@ -39,8 +40,8 @@ const updateProjectMdFiles = async (projectId, files) =>
let
matchMd
=
file
.
match
(
watchedFileReMd
);
if
(
matchMd
)
{
const
[
filename
,
basename
,
extension
]
=
matchMd
;
const
p
ath
=
projectPath
+
"
/
"
+
filename
;
updateFileMd
(
projectId
,
{
path
,
filename
,
basename
,
extension
});
const
fileP
ath
=
path
.
join
(
projectPath
,
filename
)
;
updateFileMd
(
projectId
,
{
path
:
filePath
,
filename
,
basename
,
extension
});
}
});
...
...
This diff is collapsed.
Click to expand it.
svelte-admin/src/Project/ProjectDashboard.svelte
+
4
-
0
View file @
5d6467d7
...
...
@@ -146,4 +146,8 @@
:global(.markdownContent li) {
margin-bottom: 1em;
}
:global(.markdownContent img) {
max-width:100%;
}
</style>
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment
Menu
Projects
Groups
Snippets
Help