Compare commits
3 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ace214070 | |||
| d725c9c73a | |||
| c0e4705a13 |
14 changed files with 609 additions and 752 deletions
|
|
@ -48,7 +48,7 @@ $ manyfold/cli/manyfold run -v ./experiences:/mnt/experiences
|
|||
|
||||
| environment variable | default | info |
|
||||
|-----------------------|--------------|------------------------|
|
||||
| `APPNAME` | `manyfold` | manyfold instance name |
|
||||
| `APPNAME` | `XRForge` | manyfold instance name |
|
||||
| `HOMEPAGE` | `/models` | show '/models' URL as homepage (use `/` for manyfold default) |
|
||||
| `THEME` | `default` | bootstrap theme |
|
||||
| `AFRAME_VERSION` | `1.7.0` | AFRAME version |
|
||||
|
|
@ -58,7 +58,6 @@ $ manyfold/cli/manyfold run -v ./experiences:/mnt/experiences
|
|||
| `DEV` | `` | enable development mode (disables caching, sets `bin/dev` as entrypoint) |
|
||||
| `NO_PUBLIC_ONLY` | `` | disable public only models |
|
||||
| `NO_OVERLAYFS` | `` | disable the filesystem overlay mechanism |
|
||||
| `NO_DEFAULTDB` | `` | disable the default xrforge db (activates manyfold installer) |
|
||||
| `NO_ASSETS` | `` | disable downloading assets from xrfragment.org repository |
|
||||
| `NO_DELETEBIGFILES` | `` | disable deleting big files which are older than 5 days and bigger than ($currentyear-2020) MB's |
|
||||
| `NO_PACKAGEALL` | `` | don't package all experiences every hour to /usr/src/app/public/experiences.zip |
|
||||
|
|
@ -83,6 +82,8 @@ $ manyfold/cli/manyfold run -v ./experiences:/mnt/experiences
|
|||
|
||||
> please modify the password in the settings screen of the webinterface.
|
||||
|
||||
It's also possible to enforce a default sqlite3 db via the `-v ./manyfold.sql:/manyfold/manyfold.sql` container flag.
|
||||
|
||||
# Filesystem overlay-mechanism
|
||||
|
||||
The server-image will boot `manyfold/cli/manyfold.sh boot` and check for directory `/manyfold` (in the container).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#!/bin/sh
|
||||
oci=$(which podman || which docker)
|
||||
test -n "$APPNAME" || export APPNAME=xrforge
|
||||
test -n "$APPNAME" || export APPNAME=XRForge
|
||||
test -n "$TAGLINE" || export TAGLINE="Publish single-file XR experiences to immersive networks"
|
||||
test -n "$UPLOAD_PATH" || export UPLOAD_PATH=/mnt/experiences
|
||||
test -n "$THEME" || export THEME=slate
|
||||
test -n "$HOMEPAGE" || export HOMEPAGE=/models
|
||||
|
|
@ -156,15 +157,30 @@ mount_rclone(){
|
|||
test -n "$RCLONE_REMOTE" || libraries
|
||||
}
|
||||
|
||||
set_theme(){
|
||||
test -z "$THEME" && return 0 # nothing to do
|
||||
echocolor "[$APPNAME]" "setting theme to '$THEME'"
|
||||
debug sqlite3 /config/manyfold.sqlite3 "UPDATE settings SET value = '"$THEME"' WHERE var == 'theme';"
|
||||
set_global(){
|
||||
echocolor "[$APPNAME]" "setting $1 to '$2'"
|
||||
debug sqlite3 /config/manyfold.sqlite3 'CREATE TABLE IF NOT EXISTS "settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "var" varchar NOT NULL, "value" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);'
|
||||
debug sqlite3 /config/manyfold.sqlite3 "
|
||||
INSERT OR REPLACE INTO settings (id, var, value, created_at, updated_at)
|
||||
VALUES (
|
||||
(SELECT id FROM settings WHERE var = '$1'),
|
||||
'$1',
|
||||
$2,
|
||||
COALESCE((SELECT created_at FROM settings WHERE var = '$1'), datetime('now')),
|
||||
datetime('now')
|
||||
);
|
||||
"
|
||||
}
|
||||
|
||||
set_modelpath(){
|
||||
echocolor "[$APPNAME]" "enforcing modelpath"
|
||||
debug sqlite3 /config/manyfold.sqlite3 "UPDATE settings SET value = replace('--- \"{creator}/{modelId}\"\n','\n',char(10)) WHERE var == 'model_path_template';"
|
||||
set_admin(){
|
||||
echocolor "[$APPNAME]" "adding xrforge admin"
|
||||
read -r -d '' QUERY <<EOF
|
||||
INSERT INTO users VALUES(1,'xrforge@localhost','\$2a\$12\$u/j8LRzbPiJRHmi1eV/fvOXXiKxN2vBGtNd.Pt28w.wOnq3rnfpzO','2025-07-25 10:52:56.989975','2025-07-25 12:46:27.338917','xrforge','{"models":true,"creators":true,"collections":true,"per_page":12}','{"grid_width":200,"grid_depth":200,"show_grid":true,"enable_pan_zoom":false,"background_colour":"#000000","object_colour":"#ffffff","render_style":"original"}','{"threshold":2,"heatmap":true,"keypair":true,"sorting":"frequency"}','{"missing":"danger","empty":"info","nesting":"warning","inefficient":"info","duplicate":"warning","no_image":"silent","no_3d_model":"silent","non_manifold":"warning","inside_out":"warning","no_license":"silent","no_links":"silent","no_creator":"silent","no_tags":"silent"}','{"hide_presupported_versions":true}',NULL,'2025-07-25 12:46:27.325287',NULL,NULL,0,NULL,NULL,NULL,NULL,'71863vkppj6k',1,1,1);
|
||||
EOF
|
||||
debug sqlite3 /config/manyfold.sqlite3 "$QUERY"
|
||||
debug sqlite3 /config/manyfold.sqlite3 'INSERT INTO users_roles VALUES(1,1);'
|
||||
#debug sqlite3 /config/manyfold.sqlite3 'INSERT INTO users_roles VALUES(1,4);'
|
||||
#debug sqlite3 /config/manyfold.sqlite3 "INSERT INTO sqlite_sequence VALUES('users',1);"
|
||||
}
|
||||
|
||||
set_homepage(){
|
||||
|
|
@ -176,7 +192,7 @@ set_homepage(){
|
|||
rename_app(){
|
||||
echocolor "[$APPNAME]" "renaming manyfold to $APPNAME"
|
||||
sed -i 's/title: Manyfold/title: '$APPNAME'/g' /usr/src/app/config/locales/*.yml
|
||||
sed -i 's|powered_by_html:.*|powered_by_html: Radically opensource-powered by <a href="https://forgejo.isvery.ninja/coderofsalvation/xrforge">XR Forge</a>, <a href="https://manifold.app" target="_blank">Manyfold</a>, <a href="https://xrfragment.org">XR Fragments</a> and <a href="https://nixos.org" target="_blank">NIX</a>|g' /usr/src/app/config/locales/*.yml
|
||||
sed -i 's|powered_by_html:.*|powered_by_html: Radically opensource-powered by <a href="https://manifold.app" target="_blank">Manyfold</a>, <a href="https://xrfragment.org">XR Fragments</a> and <a href="https://nixos.org" target="_blank">NIX</a>|g' /usr/src/app/config/locales/*.yml
|
||||
|
||||
sed -i 's|Models|Experiences|g' /usr/src/app/config/locales/*.yml /usr/src/app/config/locales/*/*.yml
|
||||
sed -i 's|Model|Experience|g' /usr/src/app/config/locales/*.yml /usr/src/app/config/locales/*/*.yml
|
||||
|
|
@ -222,28 +238,35 @@ get_xrfragment_assets(){
|
|||
add_lib_to_db /mnt/templates
|
||||
}
|
||||
|
||||
init_database(){
|
||||
sleep 3
|
||||
test -z "$THEME" || set_global theme "'$THEME'"
|
||||
set_admin
|
||||
set_global site_name "'$APPNAME'"
|
||||
set_global site_tagline "'$TAGLINE'"
|
||||
set_global model_tags_auto_tag_new "'build'"
|
||||
set_global model_path_template "replace('--- \"{creator}/{modelId} \"\\n','\\n',char(10))"
|
||||
#set_global about "$ABOUT"
|
||||
mount_rclone
|
||||
set_upload_path &
|
||||
force_public &
|
||||
get_xrfragment_assets
|
||||
mount_dir
|
||||
scan_libraries &
|
||||
}
|
||||
|
||||
# The new entrypoint of the docker
|
||||
boot(){
|
||||
echocolor "[$APPNAME]" "booting..."
|
||||
test -z "$NO_OVERLAYFS" && overlayfs
|
||||
test -z "$NO_DEFAULTDB" && db default
|
||||
start_syslog
|
||||
rename_app
|
||||
set_homepage
|
||||
set_theme
|
||||
set_modelpath
|
||||
mount_rclone
|
||||
set_upload_path
|
||||
force_public
|
||||
start_hook_daemon
|
||||
get_xrfragment_assets
|
||||
mount_dir
|
||||
scan_libraries &
|
||||
hook boot # emit unixy hook-event (/root/hook.d/boot/* scripts)
|
||||
|
||||
# enable development mode (disables template caching etc)
|
||||
test -n "$DEV" && {
|
||||
sed -i 's|^exec.*|exec s6-setuidgid $PUID:$PGID bin/dev|g' /usr/src/app/bin/docker-entrypoint.sh
|
||||
# sed -i 's|^exec.*|exec s6-setuidgid $PUID:$PGID bin/dev|g' /usr/src/app/bin/docker-entrypoint.sh
|
||||
sed -i 's|config.enable_reloading = false|config.enable_reloading = true|g' /usr/src/app/config/environments/production.rb
|
||||
apk add vim
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,362 +0,0 @@
|
|||
PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE IF NOT EXISTS "data_migrations" ("version" varchar NOT NULL PRIMARY KEY);
|
||||
INSERT INTO data_migrations VALUES('20221214230757');
|
||||
INSERT INTO data_migrations VALUES('20221220223040');
|
||||
INSERT INTO data_migrations VALUES('20230221174212');
|
||||
INSERT INTO data_migrations VALUES('20230308006000');
|
||||
INSERT INTO data_migrations VALUES('20230612080306');
|
||||
INSERT INTO data_migrations VALUES('20230613134254');
|
||||
INSERT INTO data_migrations VALUES('20230617222353');
|
||||
INSERT INTO data_migrations VALUES('20230628194944');
|
||||
INSERT INTO data_migrations VALUES('20240319155526');
|
||||
INSERT INTO data_migrations VALUES('20240322150022');
|
||||
INSERT INTO data_migrations VALUES('20240615085913');
|
||||
INSERT INTO data_migrations VALUES('20240731165647');
|
||||
INSERT INTO data_migrations VALUES('20240802094448');
|
||||
INSERT INTO data_migrations VALUES('20240805111500');
|
||||
INSERT INTO data_migrations VALUES('20240830121749');
|
||||
INSERT INTO data_migrations VALUES('20240830151650');
|
||||
INSERT INTO data_migrations VALUES('20240904152358');
|
||||
INSERT INTO data_migrations VALUES('20240909100000');
|
||||
INSERT INTO data_migrations VALUES('20240923114515');
|
||||
INSERT INTO data_migrations VALUES('20241013215000');
|
||||
INSERT INTO data_migrations VALUES('20241021125322');
|
||||
INSERT INTO data_migrations VALUES('20241118155027');
|
||||
INSERT INTO data_migrations VALUES('20250121164452');
|
||||
CREATE TABLE IF NOT EXISTS "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY);
|
||||
INSERT INTO schema_migrations VALUES('20210130201037');
|
||||
INSERT INTO schema_migrations VALUES('20210130203243');
|
||||
INSERT INTO schema_migrations VALUES('20210205230918');
|
||||
INSERT INTO schema_migrations VALUES('20210210153744');
|
||||
INSERT INTO schema_migrations VALUES('20210212143001');
|
||||
INSERT INTO schema_migrations VALUES('20210212143002');
|
||||
INSERT INTO schema_migrations VALUES('20210212143003');
|
||||
INSERT INTO schema_migrations VALUES('20210212143004');
|
||||
INSERT INTO schema_migrations VALUES('20210212143005');
|
||||
INSERT INTO schema_migrations VALUES('20210212143006');
|
||||
INSERT INTO schema_migrations VALUES('20210220204055');
|
||||
INSERT INTO schema_migrations VALUES('20210225232756');
|
||||
INSERT INTO schema_migrations VALUES('20210225232841');
|
||||
INSERT INTO schema_migrations VALUES('20210301230017');
|
||||
INSERT INTO schema_migrations VALUES('20210302161202');
|
||||
INSERT INTO schema_migrations VALUES('20210314185822');
|
||||
INSERT INTO schema_migrations VALUES('20210318202638');
|
||||
INSERT INTO schema_migrations VALUES('20210321164508');
|
||||
INSERT INTO schema_migrations VALUES('20210330215825');
|
||||
INSERT INTO schema_migrations VALUES('20220105233138');
|
||||
INSERT INTO schema_migrations VALUES('20220106220519');
|
||||
INSERT INTO schema_migrations VALUES('20220612220115');
|
||||
INSERT INTO schema_migrations VALUES('20220612220116');
|
||||
INSERT INTO schema_migrations VALUES('20220612220117');
|
||||
INSERT INTO schema_migrations VALUES('20220614210023');
|
||||
INSERT INTO schema_migrations VALUES('20220614211256');
|
||||
INSERT INTO schema_migrations VALUES('20220614213902');
|
||||
INSERT INTO schema_migrations VALUES('20220617122809');
|
||||
INSERT INTO schema_migrations VALUES('20220619174307');
|
||||
INSERT INTO schema_migrations VALUES('20220626152444');
|
||||
INSERT INTO schema_migrations VALUES('20220702202932');
|
||||
INSERT INTO schema_migrations VALUES('20221128165903');
|
||||
INSERT INTO schema_migrations VALUES('20221210001132');
|
||||
INSERT INTO schema_migrations VALUES('20221219204414');
|
||||
INSERT INTO schema_migrations VALUES('20221220223340');
|
||||
INSERT INTO schema_migrations VALUES('20230202210000');
|
||||
INSERT INTO schema_migrations VALUES('20230202210001');
|
||||
INSERT INTO schema_migrations VALUES('20230203150000');
|
||||
INSERT INTO schema_migrations VALUES('20230221180921');
|
||||
INSERT INTO schema_migrations VALUES('20230222155910');
|
||||
INSERT INTO schema_migrations VALUES('20230303150029');
|
||||
INSERT INTO schema_migrations VALUES('20230305180823');
|
||||
INSERT INTO schema_migrations VALUES('20230307215826');
|
||||
INSERT INTO schema_migrations VALUES('20230308004237');
|
||||
INSERT INTO schema_migrations VALUES('20230308005021');
|
||||
INSERT INTO schema_migrations VALUES('20230313000000');
|
||||
INSERT INTO schema_migrations VALUES('20230313000001');
|
||||
INSERT INTO schema_migrations VALUES('20230316184012');
|
||||
INSERT INTO schema_migrations VALUES('20230324000000');
|
||||
INSERT INTO schema_migrations VALUES('20230615135601');
|
||||
INSERT INTO schema_migrations VALUES('20230628195018');
|
||||
INSERT INTO schema_migrations VALUES('20230707082403');
|
||||
INSERT INTO schema_migrations VALUES('20230710102250');
|
||||
INSERT INTO schema_migrations VALUES('20230711111009');
|
||||
INSERT INTO schema_migrations VALUES('20240122114207');
|
||||
INSERT INTO schema_migrations VALUES('20240127143358');
|
||||
INSERT INTO schema_migrations VALUES('20240131134832');
|
||||
INSERT INTO schema_migrations VALUES('20240208143319');
|
||||
INSERT INTO schema_migrations VALUES('20240209125409');
|
||||
INSERT INTO schema_migrations VALUES('20240228130246');
|
||||
INSERT INTO schema_migrations VALUES('20240306095646');
|
||||
INSERT INTO schema_migrations VALUES('20240319155251');
|
||||
INSERT INTO schema_migrations VALUES('20240319155903');
|
||||
INSERT INTO schema_migrations VALUES('20240322143621');
|
||||
INSERT INTO schema_migrations VALUES('20240410221112');
|
||||
INSERT INTO schema_migrations VALUES('20240410222922');
|
||||
INSERT INTO schema_migrations VALUES('20240418112821');
|
||||
INSERT INTO schema_migrations VALUES('20240423102250');
|
||||
INSERT INTO schema_migrations VALUES('20240610120318');
|
||||
INSERT INTO schema_migrations VALUES('20240614085913');
|
||||
INSERT INTO schema_migrations VALUES('20240701142651');
|
||||
INSERT INTO schema_migrations VALUES('20240703103707');
|
||||
INSERT INTO schema_migrations VALUES('20240703160732');
|
||||
INSERT INTO schema_migrations VALUES('20240727113215');
|
||||
INSERT INTO schema_migrations VALUES('20240727113216');
|
||||
INSERT INTO schema_migrations VALUES('20240727113217');
|
||||
INSERT INTO schema_migrations VALUES('20240731165646');
|
||||
INSERT INTO schema_migrations VALUES('20240827155630');
|
||||
INSERT INTO schema_migrations VALUES('20240904151944');
|
||||
INSERT INTO schema_migrations VALUES('20240924122004');
|
||||
INSERT INTO schema_migrations VALUES('20240926162407');
|
||||
INSERT INTO schema_migrations VALUES('20241004194445');
|
||||
INSERT INTO schema_migrations VALUES('20241007182824');
|
||||
INSERT INTO schema_migrations VALUES('20241009122540');
|
||||
INSERT INTO schema_migrations VALUES('20241015090803');
|
||||
INSERT INTO schema_migrations VALUES('20241017093301');
|
||||
INSERT INTO schema_migrations VALUES('20241017113112');
|
||||
INSERT INTO schema_migrations VALUES('20241021124608');
|
||||
INSERT INTO schema_migrations VALUES('20241025110218');
|
||||
INSERT INTO schema_migrations VALUES('20241105121830');
|
||||
INSERT INTO schema_migrations VALUES('20241122121621');
|
||||
INSERT INTO schema_migrations VALUES('20241128162213');
|
||||
INSERT INTO schema_migrations VALUES('20241128162214');
|
||||
INSERT INTO schema_migrations VALUES('20250114105808');
|
||||
INSERT INTO schema_migrations VALUES('20250121105010');
|
||||
INSERT INTO schema_migrations VALUES('20250122171731');
|
||||
INSERT INTO schema_migrations VALUES('20250222000000');
|
||||
INSERT INTO schema_migrations VALUES('20250305171530');
|
||||
INSERT INTO schema_migrations VALUES('20250407160721');
|
||||
INSERT INTO schema_migrations VALUES('20250407160722');
|
||||
INSERT INTO schema_migrations VALUES('20250408111644');
|
||||
INSERT INTO schema_migrations VALUES('20250408145956');
|
||||
INSERT INTO schema_migrations VALUES('20250409120155');
|
||||
INSERT INTO schema_migrations VALUES('20250409125753');
|
||||
INSERT INTO schema_migrations VALUES('20250423094525');
|
||||
INSERT INTO schema_migrations VALUES('20250425104619');
|
||||
INSERT INTO schema_migrations VALUES('20250520111046');
|
||||
INSERT INTO schema_migrations VALUES('20250609210440');
|
||||
INSERT INTO schema_migrations VALUES('20250620141805');
|
||||
INSERT INTO schema_migrations VALUES('20250621223410');
|
||||
INSERT INTO schema_migrations VALUES('20250629212656');
|
||||
INSERT INTO schema_migrations VALUES('20250716093106');
|
||||
INSERT INTO schema_migrations VALUES('20250724094951');
|
||||
INSERT INTO schema_migrations VALUES('20250806142734');
|
||||
CREATE TABLE IF NOT EXISTS "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
INSERT INTO ar_internal_metadata VALUES('environment','production','2025-07-25 10:52:31.380052','2025-07-25 10:52:31.380054');
|
||||
CREATE TABLE IF NOT EXISTS "libraries" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "path" varchar NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "notes" varchar, "caption" varchar, "name" varchar, "tag_regex" text, "icon" text, "storage_service" varchar DEFAULT 'filesystem' NOT NULL, "s3_endpoint" varchar DEFAULT NULL, "s3_region" varchar DEFAULT NULL, "s3_bucket" varchar DEFAULT NULL, "s3_access_key_id" varchar DEFAULT NULL, "s3_secret_access_key" varchar DEFAULT NULL, "public_id" varchar, "s3_path_style" boolean DEFAULT 1 NOT NULL);
|
||||
INSERT INTO libraries VALUES(6,'/mnt/experiences','2025-08-14','2025-08-14','','','experiences',NULL,'','filesystem','','','','','','experiences',1);
|
||||
CREATE TABLE IF NOT EXISTS "tags" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "created_at" datetime, "updated_at" datetime, "taggings_count" integer DEFAULT 0);
|
||||
CREATE TABLE IF NOT EXISTS "taggings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "tag_id" integer, "taggable_type" varchar, "taggable_id" integer, "tagger_type" varchar, "tagger_id" integer, "context" varchar(128), "created_at" datetime, CONSTRAINT "fk_rails_9fcd2e236b"
|
||||
FOREIGN KEY ("tag_id")
|
||||
REFERENCES "tags" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "links" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "url" varchar, "linkable_type" varchar, "linkable_id" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "synced_at" datetime(6));
|
||||
INSERT INTO links VALUES(1,'https://xrfragment.org','Creator',1,'2025-08-14 12:57:19.685425','2025-08-14 12:57:19.685425',NULL);
|
||||
CREATE TABLE IF NOT EXISTS "settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "var" varchar NOT NULL, "value" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
INSERT INTO settings VALUES(1,'default_library','6','2025-07-25 10:58:00.004576','2025-07-28 13:30:03.381376');
|
||||
INSERT INTO settings VALUES(2,'site_name',replace('--- XRForge\n','\n',char(10)),'2025-07-25 10:59:04.496016','2025-07-25 10:59:04.496016');
|
||||
INSERT INTO settings VALUES(3,'site_tagline',replace('--- Self-sovereign XR Experiences based on 3D files & URLs\n','\n',char(10)),'2025-07-25 10:59:04.519264','2025-07-25 10:59:04.519264');
|
||||
INSERT INTO settings VALUES(4,'theme','vapor','2025-07-25 10:59:04.522670','2025-07-28 13:47:54.690364');
|
||||
INSERT INTO settings VALUES(5,'about',replace('--- ''''\n','\n',char(10)),'2025-07-25 10:59:04.527612','2025-07-25 10:59:04.527612');
|
||||
INSERT INTO settings VALUES(6,'rules',replace('--- ''''\n','\n',char(10)),'2025-07-25 10:59:04.531378','2025-07-25 10:59:04.531378');
|
||||
INSERT INTO settings VALUES(7,'support_link',replace('--- https://forgejo.isvery.ninja/coderofsalvation/xrforge\n','\n',char(10)),'2025-07-25 10:59:04.533678','2025-07-25 10:59:04.533678');
|
||||
INSERT INTO settings VALUES(8,'site_icon',replace('--- ''''\n','\n',char(10)),'2025-07-25 10:59:04.536228','2025-07-25 14:19:06.192651');
|
||||
INSERT INTO settings VALUES(9,'model_path_template',replace('--- "{creator}/{modelId}"\n','\n',char(10)),'2025-07-28 15:57:18.598798','2025-07-28 15:57:18.598798');
|
||||
INSERT INTO settings VALUES(10,'parse_metadata_from_path',replace('--- true\n','\n',char(10)),'2025-07-28 15:57:18.624917','2025-07-28 15:57:18.624917');
|
||||
INSERT INTO settings VALUES(11,'safe_folder_names',replace('--- true\n','\n',char(10)),'2025-07-28 15:57:18.627224','2025-07-28 15:57:18.627224');
|
||||
INSERT INTO settings VALUES(12,'model_ignored_files',replace('---\n- !ruby/regexp /^\.[^\.]+/\n- !ruby/regexp /.*\/@eaDir\/.*/\n- !ruby/regexp /__MACOSX/\n','\n',char(10)),'2025-07-28 15:57:18.633182','2025-07-28 15:57:18.633182');
|
||||
INSERT INTO settings VALUES(13,'model_tags_filter_stop_words',replace('--- true\n','\n',char(10)),'2025-07-28 15:57:18.637858','2025-07-28 15:57:18.637858');
|
||||
INSERT INTO settings VALUES(14,'model_tags_tag_model_directory_name',replace('--- false\n','\n',char(10)),'2025-07-28 15:57:18.640351','2025-07-28 15:57:18.640351');
|
||||
INSERT INTO settings VALUES(15,'model_tags_stop_words_locale',replace('--- en\n','\n',char(10)),'2025-07-28 15:57:18.643185','2025-07-28 15:57:18.643185');
|
||||
INSERT INTO settings VALUES(16,'model_tags_custom_stop_words',replace('---\n- png\n- jpeg\n- jpg\n- jpe\n- pjpeg\n- gif\n- bmp\n- tiff\n- tif\n- svg\n- webp\n- threeds\n- 3ds\n- amf\n- ldr\n- mpd\n- scad\n- dwg\n- dxf\n- threemf\n- 3mf\n- gltf\n- glb\n- iges\n- igs\n- mtl\n- obj\n- step\n- stp\n- stl\n- collada\n- dae\n- draco\n- drc\n- vrml\n- wrl\n- abc\n- blend\n- brep\n- cheetah3d\n- jas\n- fbx\n- fcstd\n- f3d\n- f3z\n- ipt\n- iam\n- maya\n- ma\n- mb\n- mix\n- modo\n- lxo\n- ply\n- sketchup\n- skp\n- sldprt\n- hfp\n- speedtree\n- spm\n- x3d\n- gcode\n- bgcode\n- lychee\n- lys\n- lyt\n- chitubox\n- ctb\n- mpeg\n- mpg\n- mpe\n- webm\n- mp4\n- m4v\n- html\n- xhtml\n- text\n- txt\n- pdf\n- md\n- doc\n- docx\n- bin\n- gbr\n- gerber\n- geb\n- gb\n- gbrjob\n- drl\n- kicad_pro\n- pro\n- kicad_mod\n- kicad_pcb\n- kicad_sym\n- kicad_sch\n- sch\n- kicad_wks\n- zip\n- gzip\n- gz\n- rar\n- sevenz\n- 7z\n- bz2\n','\n',char(10)),'2025-07-28 15:57:18.645648','2025-07-28 15:57:18.645648');
|
||||
INSERT INTO settings VALUES(17,'model_tags_auto_tag_new',replace('--- "!new"\n','\n',char(10)),'2025-07-28 15:57:18.648518','2025-07-28 15:57:18.648518');
|
||||
CREATE TABLE IF NOT EXISTS "problems" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "problematic_type" varchar, "problematic_id" integer, "category" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "note" varchar DEFAULT NULL, "ignored" boolean DEFAULT 0 NOT NULL, "public_id" varchar, "in_progress" boolean DEFAULT 0 NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "favorites" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "favoritable_type" varchar NOT NULL, "favoritable_id" integer NOT NULL, "favoritor_type" varchar NOT NULL, "favoritor_id" integer NOT NULL, "scope" varchar DEFAULT 'printed' NOT NULL, "blocked" boolean DEFAULT 0 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "flipper_features" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "flipper_gates" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "feature_key" varchar NOT NULL, "key" varchar NOT NULL, "value" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "roles" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "resource_type" varchar, "resource_id" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
INSERT INTO roles VALUES(1,'administrator',NULL,NULL,'2025-07-25 10:52:35.066502','2025-07-25 10:52:35.066502');
|
||||
INSERT INTO roles VALUES(2,'moderator',NULL,NULL,'2025-07-25 10:52:35.079751','2025-07-25 10:52:35.079751');
|
||||
INSERT INTO roles VALUES(3,'contributor',NULL,NULL,'2025-07-25 10:52:35.081798','2025-07-25 10:52:35.081798');
|
||||
INSERT INTO roles VALUES(4,'member',NULL,NULL,'2025-07-25 10:52:35.083068','2025-07-25 10:52:35.083068');
|
||||
CREATE TABLE IF NOT EXISTS "users_roles" ("user_id" integer, "role_id" integer);
|
||||
INSERT INTO users_roles VALUES(1,4);
|
||||
INSERT INTO users_roles VALUES(1,1);
|
||||
CREATE TABLE IF NOT EXISTS "users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar DEFAULT '' NOT NULL, "encrypted_password" varchar DEFAULT '' NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "username" varchar NOT NULL, "pagination_settings" json DEFAULT '{"models":true,"creators":true,"collections":true,"per_page":12}', "renderer_settings" json DEFAULT '{"grid_width":200,"grid_depth":200,"show_grid":true,"enable_pan_zoom":false,"background_colour":"#000000","object_colour":"#ffffff","render_style":"original"}', "tag_cloud_settings" json DEFAULT '{"threshold":2,"heatmap":true,"keypair":true,"sorting":"frequency"}', "problem_settings" json DEFAULT '{"missing":"danger","empty":"info","nesting":"warning","inefficient":"info","duplicate":"warning","no_image":"silent","no_3d_model":"silent","non_manifold":"warning","inside_out":"warning","no_license":"silent","no_links":"silent","no_creator":"silent","no_tags":"silent"}', "file_list_settings" json DEFAULT '{"hide_presupported_versions":true}', "reset_password_token" varchar, "remember_created_at" datetime(6), "reset_password_sent_at" datetime(6), "interface_language" varchar, "failed_attempts" integer DEFAULT 0 NOT NULL, "locked_at" datetime(6), "auth_provider" varchar, "auth_uid" varchar, "sensitive_content_handling" varchar DEFAULT NULL, "public_id" varchar, "approved" boolean DEFAULT 1 NOT NULL, "quota" integer DEFAULT 1 NOT NULL, "quota_use_site_default" boolean DEFAULT 1 NOT NULL);
|
||||
INSERT INTO users VALUES(1,'xrforge@localhost','$2a$12$u/j8LRzbPiJRHmi1eV/fvOXXiKxN2vBGtNd.Pt28w.wOnq3rnfpzO','2025-07-25 10:52:56.989975','2025-07-25 12:46:27.338917','xrforge','{"models":true,"creators":true,"collections":true,"per_page":12}','{"grid_width":200,"grid_depth":200,"show_grid":true,"enable_pan_zoom":false,"background_colour":"#000000","object_colour":"#ffffff","render_style":"original"}','{"threshold":2,"heatmap":true,"keypair":true,"sorting":"frequency"}','{"missing":"danger","empty":"info","nesting":"warning","inefficient":"info","duplicate":"warning","no_image":"silent","no_3d_model":"silent","non_manifold":"warning","inside_out":"warning","no_license":"silent","no_links":"silent","no_creator":"silent","no_tags":"silent"}','{"hide_presupported_versions":true}',NULL,'2025-07-25 12:46:27.325287',NULL,NULL,0,NULL,NULL,NULL,NULL,'71863vkppj6k',1,1,1);
|
||||
CREATE TABLE IF NOT EXISTS "federails_followings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "actor_id" integer NOT NULL, "target_actor_id" integer NOT NULL, "status" integer DEFAULT 0, "federated_url" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "uuid" varchar DEFAULT NULL, CONSTRAINT "fk_rails_2e62338faa"
|
||||
FOREIGN KEY ("actor_id")
|
||||
REFERENCES "federails_actors" ("id")
|
||||
, CONSTRAINT "fk_rails_4a2870c181"
|
||||
FOREIGN KEY ("target_actor_id")
|
||||
REFERENCES "federails_actors" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "federails_activities" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "entity_type" varchar NOT NULL, "entity_id" integer NOT NULL, "action" varchar NOT NULL, "actor_id" integer NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "uuid" varchar DEFAULT NULL, CONSTRAINT "fk_rails_85ef6259df"
|
||||
FOREIGN KEY ("actor_id")
|
||||
REFERENCES "federails_actors" ("id")
|
||||
);
|
||||
INSERT INTO federails_activities VALUES(1,'Federails::Actor',2,'Create',1,'2025-08-14 12:57:19.593979','2025-08-14 12:57:19.737880','22e24c27-09ac-4f61-8897-1e176f16fcf7');
|
||||
CREATE TABLE IF NOT EXISTS "caber_relations" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "subject_type" varchar, "subject_id" integer, "permission" varchar, "object_type" varchar NOT NULL, "object_id" integer NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
INSERT INTO caber_relations VALUES(1,'User',1,'own','Creator',1,'2025-08-14 12:57:19.679313','2025-08-14 12:57:19.679313');
|
||||
INSERT INTO caber_relations VALUES(2,'Role',4,'view','Creator',1,'2025-08-14 12:57:19.762509','2025-08-14 12:57:19.762509');
|
||||
CREATE TABLE IF NOT EXISTS "federails_moderation_reports" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "federated_url" varchar, "federails_actor_id" integer, "content" varchar, "object_type" varchar, "object_id" integer, "resolved_at" datetime(6), "resolution" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, CONSTRAINT "fk_rails_a5cda24d4c"
|
||||
FOREIGN KEY ("federails_actor_id")
|
||||
REFERENCES "federails_actors" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "federails_moderation_domain_blocks" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "domain" varchar NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "comments" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "public_id" varchar NOT NULL, "commenter_type" varchar, "commenter_id" integer, "commentable_type" varchar NOT NULL, "commentable_id" integer NOT NULL, "comment" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "system" boolean DEFAULT 0 NOT NULL, "sensitive" boolean DEFAULT 0 NOT NULL, "federated_url" varchar, "federails_actor_id" integer, CONSTRAINT "fk_rails_3a181ceff0"
|
||||
FOREIGN KEY ("federails_actor_id")
|
||||
REFERENCES "federails_actors" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "oauth_applications" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "uid" varchar NOT NULL, "secret" varchar NOT NULL, "redirect_uri" text, "scopes" varchar DEFAULT '' NOT NULL, "confidential" boolean DEFAULT 1 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "owner_id" bigint, "owner_type" varchar);
|
||||
CREATE TABLE IF NOT EXISTS "oauth_access_grants" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "resource_owner_id" integer NOT NULL, "application_id" integer NOT NULL, "token" varchar NOT NULL, "expires_in" integer NOT NULL, "redirect_uri" text NOT NULL, "scopes" varchar DEFAULT '' NOT NULL, "created_at" datetime(6) NOT NULL, "revoked_at" datetime(6), CONSTRAINT "fk_rails_b4b53e07b8"
|
||||
FOREIGN KEY ("application_id")
|
||||
REFERENCES "oauth_applications" ("id")
|
||||
, CONSTRAINT "fk_rails_330c32d8d9"
|
||||
FOREIGN KEY ("resource_owner_id")
|
||||
REFERENCES "users" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "oauth_access_tokens" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "resource_owner_id" integer, "application_id" integer NOT NULL, "token" varchar NOT NULL, "refresh_token" varchar, "expires_in" integer, "scopes" varchar, "created_at" datetime(6) NOT NULL, "revoked_at" datetime(6), "previous_refresh_token" varchar DEFAULT '' NOT NULL, CONSTRAINT "fk_rails_732cb83ab7"
|
||||
FOREIGN KEY ("application_id")
|
||||
REFERENCES "oauth_applications" ("id")
|
||||
, CONSTRAINT "fk_rails_ee63f25419"
|
||||
FOREIGN KEY ("resource_owner_id")
|
||||
REFERENCES "users" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "federails_actors" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "federated_url" varchar, "username" varchar, "server" varchar, "inbox_url" varchar, "outbox_url" varchar, "followers_url" varchar, "followings_url" varchar, "profile_url" varchar, "entity_id" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "entity_type" varchar DEFAULT NULL, "public_key" text, "private_key" text, "uuid" varchar, "extensions" json, "local" boolean DEFAULT 0 NOT NULL, "actor_type" varchar, "tombstoned_at" datetime(6));
|
||||
INSERT INTO federails_actors VALUES(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-07-25 10:52:57.029315','2025-07-25 10:52:57.029315','User',NULL,NULL,'eb64d114-1bc7-4cb3-8be6-350d23ccfb3e',NULL,1,NULL,NULL);
|
||||
INSERT INTO federails_actors VALUES(2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-08-14 12:57:19.669133','2025-08-14 12:57:19.669133','Creator',NULL,NULL,'a544a58c-52be-4013-9415-440a9014b4c8',NULL,1,NULL,NULL);
|
||||
CREATE TABLE IF NOT EXISTS "model_files" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "filename" varchar, "model_id" integer NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "presupported" boolean DEFAULT 0 NOT NULL, "y_up" boolean DEFAULT 0 NOT NULL, "digest" varchar, "notes" text, "caption" text, "size" bigint, "presupported_version_id" integer, "attachment_data" json, "public_id" varchar, "filename_lower" varchar GENERATED ALWAYS AS (LOWER(filename)) STORED, "previewable" boolean DEFAULT 0 NOT NULL, CONSTRAINT "fk_rails_b5ac05b6e3"
|
||||
FOREIGN KEY ("presupported_version_id")
|
||||
REFERENCES "model_files" ("id")
|
||||
, CONSTRAINT "fk_rails_8e378ff647"
|
||||
FOREIGN KEY ("model_id")
|
||||
REFERENCES "models" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "altcha_solutions" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "algorithm" varchar, "challenge" varchar, "salt" varchar, "signature" varchar, "number" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "models" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "path" varchar NOT NULL, "library_id" integer NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "preview_file_id" integer, "creator_id" integer, "notes" text, "caption" text, "collection_id" integer, "slug" varchar, "license" varchar, "public_id" varchar, "name_lower" varchar GENERATED ALWAYS AS (LOWER(name)) STORED, "sensitive" boolean DEFAULT 0 NOT NULL, "indexable" varchar, "ai_indexable" varchar, CONSTRAINT "fk_rails_cdf016e15c"
|
||||
FOREIGN KEY ("collection_id")
|
||||
REFERENCES "collections" ("id")
|
||||
, CONSTRAINT "fk_rails_aaa717f5bb"
|
||||
FOREIGN KEY ("library_id")
|
||||
REFERENCES "libraries" ("id")
|
||||
, CONSTRAINT "fk_rails_3b8b50d3f3"
|
||||
FOREIGN KEY ("creator_id")
|
||||
REFERENCES "creators" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "creators" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "notes" text, "caption" text, "slug" varchar, "public_id" varchar, "name_lower" varchar GENERATED ALWAYS AS (LOWER(name)) STORED, "indexable" varchar, "ai_indexable" varchar);
|
||||
INSERT INTO creators VALUES(1,'xrfragments','2025-08-14 12:57:19.593979','2025-08-14 12:57:19.593979','XR Fragments is an open specification for hyperlinking & deeplinking 3D fileformats .\nTurn 3D files into linkable AR/VR websites .\n3D files with XR Fragments enable interoperable, networkable and interactions via so-called extras and promote URL standards','deeplinking and adressing 3D objects using URI''s','xrfragments','bdb7rrdjwtdm','yes',NULL);
|
||||
CREATE TABLE IF NOT EXISTS "collections" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "notes" text, "caption" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "collection_id" integer, "slug" varchar, "public_id" varchar, "name_lower" varchar GENERATED ALWAYS AS (LOWER(name)) STORED, "creator_id" integer, "indexable" varchar, "ai_indexable" varchar, CONSTRAINT "fk_rails_63724415e9"
|
||||
FOREIGN KEY ("collection_id")
|
||||
REFERENCES "collections" ("id")
|
||||
, CONSTRAINT "fk_rails_ab2fec83b3"
|
||||
FOREIGN KEY ("creator_id")
|
||||
REFERENCES "creators" ("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "fasp_client_providers" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "uuid" varchar, "name" varchar, "base_url" varchar, "server_id" varchar, "public_key" varchar, "ed25519_signing_key" varchar, "status" integer, "capabilities" json, "privacy_policy" json, "sign_in_url" varchar, "contact_email" varchar, "fediverse_account" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
|
||||
INSERT INTO sqlite_sequence VALUES('taggings',0);
|
||||
INSERT INTO sqlite_sequence VALUES('users',1);
|
||||
INSERT INTO sqlite_sequence VALUES('comments',0);
|
||||
INSERT INTO sqlite_sequence VALUES('oauth_access_grants',0);
|
||||
INSERT INTO sqlite_sequence VALUES('oauth_access_tokens',0);
|
||||
INSERT INTO sqlite_sequence VALUES('federails_actors',2);
|
||||
INSERT INTO sqlite_sequence VALUES('model_files',0);
|
||||
INSERT INTO sqlite_sequence VALUES('models',0);
|
||||
INSERT INTO sqlite_sequence VALUES('creators',1);
|
||||
INSERT INTO sqlite_sequence VALUES('collections',0);
|
||||
INSERT INTO sqlite_sequence VALUES('roles',4);
|
||||
INSERT INTO sqlite_sequence VALUES('libraries',6);
|
||||
INSERT INTO sqlite_sequence VALUES('settings',17);
|
||||
INSERT INTO sqlite_sequence VALUES('caber_relations',2);
|
||||
INSERT INTO sqlite_sequence VALUES('links',1);
|
||||
INSERT INTO sqlite_sequence VALUES('federails_activities',1);
|
||||
CREATE UNIQUE INDEX "index_tags_on_name" ON "tags" ("name");
|
||||
CREATE UNIQUE INDEX "taggings_idx" ON "taggings" ("tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type");
|
||||
CREATE INDEX "taggings_taggable_context_idx" ON "taggings" ("taggable_id", "taggable_type", "context");
|
||||
CREATE INDEX "index_taggings_on_taggable_type" ON "taggings" ("taggable_type");
|
||||
CREATE INDEX "index_taggings_on_context" ON "taggings" ("context");
|
||||
CREATE INDEX "index_taggings_on_tagger_id_and_tagger_type" ON "taggings" ("tagger_id", "tagger_type");
|
||||
CREATE INDEX "taggings_idy" ON "taggings" ("taggable_id", "taggable_type", "tagger_id", "context");
|
||||
CREATE INDEX "index_links_on_linkable" ON "links" ("linkable_type", "linkable_id");
|
||||
CREATE UNIQUE INDEX "index_settings_on_var" ON "settings" ("var");
|
||||
CREATE INDEX "index_problems_on_problematic" ON "problems" ("problematic_type", "problematic_id");
|
||||
CREATE INDEX "index_favorites_on_favoritor" ON "favorites" ("favoritor_type", "favoritor_id");
|
||||
CREATE INDEX "index_favorites_on_scope" ON "favorites" ("scope");
|
||||
CREATE INDEX "index_favorites_on_blocked" ON "favorites" ("blocked");
|
||||
CREATE INDEX "fk_favorites" ON "favorites" ("favoritor_id", "favoritor_type");
|
||||
CREATE INDEX "fk_favoritables" ON "favorites" ("favoritable_id", "favoritable_type");
|
||||
CREATE UNIQUE INDEX "uniq_favorites__and_favoritables" ON "favorites" ("favoritable_type", "favoritable_id", "favoritor_type", "favoritor_id", "scope");
|
||||
CREATE UNIQUE INDEX "index_problems_on_category_and_problematic_id_and_type" ON "problems" ("category", "problematic_id", "problematic_type");
|
||||
CREATE UNIQUE INDEX "index_flipper_features_on_key" ON "flipper_features" ("key");
|
||||
CREATE UNIQUE INDEX "index_flipper_gates_on_feature_key_and_key_and_value" ON "flipper_gates" ("feature_key", "key", "value");
|
||||
CREATE INDEX "index_roles_on_resource" ON "roles" ("resource_type", "resource_id");
|
||||
CREATE INDEX "index_users_roles_on_role_id" ON "users_roles" ("role_id");
|
||||
CREATE INDEX "index_roles_on_name_and_resource_type_and_resource_id" ON "roles" ("name", "resource_type", "resource_id");
|
||||
CREATE INDEX "index_users_roles_on_user_id_and_role_id" ON "users_roles" ("user_id", "role_id");
|
||||
CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email");
|
||||
CREATE UNIQUE INDEX "index_users_on_username" ON "users" ("username");
|
||||
CREATE UNIQUE INDEX "index_users_on_reset_password_token" ON "users" ("reset_password_token");
|
||||
CREATE INDEX "index_federails_followings_on_target_actor_id" ON "federails_followings" ("target_actor_id");
|
||||
CREATE UNIQUE INDEX "index_federails_followings_on_actor_id_and_target_actor_id" ON "federails_followings" ("actor_id", "target_actor_id");
|
||||
CREATE INDEX "index_federails_activities_on_entity" ON "federails_activities" ("entity_type", "entity_id");
|
||||
CREATE INDEX "index_federails_activities_on_actor_id" ON "federails_activities" ("actor_id");
|
||||
CREATE INDEX "index_caber_relations_on_subject" ON "caber_relations" ("subject_type", "subject_id");
|
||||
CREATE INDEX "index_caber_relations_on_object" ON "caber_relations" ("object_type", "object_id");
|
||||
CREATE UNIQUE INDEX "idx_on_subject_id_subject_type_object_id_object_typ_a279b094be" ON "caber_relations" ("subject_id", "subject_type", "object_id", "object_type");
|
||||
CREATE INDEX "index_problems_on_public_id" ON "problems" ("public_id");
|
||||
CREATE INDEX "index_libraries_on_public_id" ON "libraries" ("public_id");
|
||||
CREATE UNIQUE INDEX "index_federails_activities_on_uuid" ON "federails_activities" ("uuid");
|
||||
CREATE UNIQUE INDEX "index_federails_followings_on_uuid" ON "federails_followings" ("uuid");
|
||||
CREATE INDEX "index_users_on_public_id" ON "users" ("public_id");
|
||||
CREATE INDEX "index_users_on_approved" ON "users" ("approved");
|
||||
CREATE INDEX "index_federails_moderation_reports_on_federails_actor_id" ON "federails_moderation_reports" ("federails_actor_id");
|
||||
CREATE INDEX "index_federails_moderation_reports_on_object" ON "federails_moderation_reports" ("object_type", "object_id");
|
||||
CREATE UNIQUE INDEX "index_federails_moderation_domain_blocks_on_domain" ON "federails_moderation_domain_blocks" ("domain");
|
||||
CREATE UNIQUE INDEX "index_comments_on_public_id" ON "comments" ("public_id");
|
||||
CREATE INDEX "index_comments_on_commenter" ON "comments" ("commenter_type", "commenter_id");
|
||||
CREATE INDEX "index_comments_on_commentable" ON "comments" ("commentable_type", "commentable_id");
|
||||
CREATE INDEX "index_comments_on_federails_actor_id" ON "comments" ("federails_actor_id");
|
||||
CREATE UNIQUE INDEX "index_oauth_applications_on_uid" ON "oauth_applications" ("uid");
|
||||
CREATE INDEX "index_oauth_access_grants_on_resource_owner_id" ON "oauth_access_grants" ("resource_owner_id");
|
||||
CREATE INDEX "index_oauth_access_grants_on_application_id" ON "oauth_access_grants" ("application_id");
|
||||
CREATE UNIQUE INDEX "index_oauth_access_grants_on_token" ON "oauth_access_grants" ("token");
|
||||
CREATE INDEX "index_oauth_access_tokens_on_resource_owner_id" ON "oauth_access_tokens" ("resource_owner_id");
|
||||
CREATE INDEX "index_oauth_access_tokens_on_application_id" ON "oauth_access_tokens" ("application_id");
|
||||
CREATE UNIQUE INDEX "index_oauth_access_tokens_on_token" ON "oauth_access_tokens" ("token");
|
||||
CREATE UNIQUE INDEX "index_oauth_access_tokens_on_refresh_token" ON "oauth_access_tokens" ("refresh_token");
|
||||
CREATE INDEX "index_oauth_applications_on_owner_id_and_owner_type" ON "oauth_applications" ("owner_id", "owner_type");
|
||||
CREATE UNIQUE INDEX "index_federails_actors_on_federated_url" ON "federails_actors" ("federated_url");
|
||||
CREATE UNIQUE INDEX "index_federails_actors_on_entity" ON "federails_actors" ("entity_type", "entity_id");
|
||||
CREATE UNIQUE INDEX "index_federails_actors_on_uuid" ON "federails_actors" ("uuid");
|
||||
CREATE INDEX "index_model_files_on_model_id" ON "model_files" ("model_id");
|
||||
CREATE INDEX "index_model_files_on_digest" ON "model_files" ("digest");
|
||||
CREATE INDEX "index_model_files_on_presupported_version_id" ON "model_files" ("presupported_version_id");
|
||||
CREATE UNIQUE INDEX "index_model_files_on_filename_and_model_id" ON "model_files" ("filename", "model_id");
|
||||
CREATE INDEX "index_model_files_on_public_id" ON "model_files" ("public_id");
|
||||
CREATE INDEX "index_model_files_on_filename_lower" ON "model_files" ("filename_lower");
|
||||
CREATE INDEX "index_links_on_linkable_id_and_linkable_type_and_url" ON "links" ("linkable_id", "linkable_type", "url");
|
||||
CREATE UNIQUE INDEX "index_altcha_solutions" ON "altcha_solutions" ("algorithm", "challenge", "salt", "signature", "number");
|
||||
CREATE INDEX "index_models_on_library_id" ON "models" ("library_id");
|
||||
CREATE INDEX "index_models_on_creator_id" ON "models" ("creator_id");
|
||||
CREATE INDEX "index_models_on_preview_file_id" ON "models" ("preview_file_id");
|
||||
CREATE INDEX "index_models_on_collection_id" ON "models" ("collection_id");
|
||||
CREATE INDEX "index_models_on_slug" ON "models" ("slug");
|
||||
CREATE UNIQUE INDEX "index_models_on_path_and_library_id" ON "models" ("path", "library_id");
|
||||
CREATE INDEX "index_models_on_public_id" ON "models" ("public_id");
|
||||
CREATE INDEX "index_models_on_name_lower" ON "models" ("name_lower");
|
||||
CREATE UNIQUE INDEX "index_creators_on_name" ON "creators" ("name");
|
||||
CREATE UNIQUE INDEX "index_creators_on_slug" ON "creators" ("slug");
|
||||
CREATE INDEX "index_creators_on_public_id" ON "creators" ("public_id");
|
||||
CREATE INDEX "index_creators_on_name_lower" ON "creators" ("name_lower");
|
||||
CREATE INDEX "index_collections_on_collection_id" ON "collections" ("collection_id");
|
||||
CREATE UNIQUE INDEX "index_collections_on_name" ON "collections" ("name");
|
||||
CREATE UNIQUE INDEX "index_collections_on_slug" ON "collections" ("slug");
|
||||
CREATE INDEX "index_collections_on_public_id" ON "collections" ("public_id");
|
||||
CREATE INDEX "index_collections_on_name_lower" ON "collections" ("name_lower");
|
||||
CREATE INDEX "index_collections_on_creator_id" ON "collections" ("creator_id");
|
||||
CREATE INDEX "index_models_on_created_at" ON "models" ("created_at");
|
||||
CREATE INDEX "index_models_on_updated_at" ON "models" ("updated_at");
|
||||
CREATE INDEX "index_creators_on_created_at" ON "creators" ("created_at");
|
||||
CREATE INDEX "index_creators_on_updated_at" ON "creators" ("updated_at");
|
||||
CREATE INDEX "index_collections_on_created_at" ON "collections" ("created_at");
|
||||
CREATE INDEX "index_collections_on_updated_at" ON "collections" ("updated_at");
|
||||
CREATE INDEX "index_links_on_url" ON "links" ("url");
|
||||
COMMIT;
|
||||
|
|
@ -2,5 +2,5 @@
|
|||
test -z "$GODOT_VERSION" && exit 0 # nothing to do
|
||||
wget "https://github.com/godotengine/godot/releases/download/${GODOT_VERSION}/Godot_v${GODOT_VERSION}_web_editor.zip" -O /root/godot.zip
|
||||
cd /usr/src/app/public/godot
|
||||
unzip /root/godot.zip
|
||||
unzip -o /root/godot.zip
|
||||
cp index.override.html index.html # make index.html autoload a manyfold zip-file (passed via HTTP query)
|
||||
|
|
|
|||
2
manyfold/root/hook.d/boot/init_database.sh
Executable file
2
manyfold/root/hook.d/boot/init_database.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
/manyfold/cli/manyfold.sh init_database
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/sh
|
||||
dir="$(dirname $1)"
|
||||
cd "$dir"
|
||||
echo "[package_experience.sh] zipping experience.zip"
|
||||
zip -D ".xrforge/experience.zip * | tee -a .xrforge/log.txt
|
||||
0
manyfold/root/hook.d/experience_updated/300-package_godot_zip.sh
Executable file → Normal file
0
manyfold/root/hook.d/experience_updated/300-package_godot_zip.sh
Executable file → Normal file
|
|
@ -19,77 +19,89 @@ begin
|
|||
# Read and parse the JSON file
|
||||
data = JSON.parse( File.read( "datapackage.json" ) )
|
||||
|
||||
logfile = File.join( File.dirname(filename), ".xrforge/log.txt" )
|
||||
if data['keywords'].empty? || data['keywords'].include?('janusxr')
|
||||
|
||||
XRForge.log("✅ starting build janusXR XR scene", logfile)
|
||||
logfile = File.join( File.dirname(filename), ".xrforge/log.txt" )
|
||||
|
||||
# Extract the desired field (assuming the field is named 'model_file')
|
||||
thumb_file = data['image']
|
||||
XRForge.log("✅ starting build janusXR XR scene", logfile)
|
||||
|
||||
XRForge.log("✅ thumbnail sidecar-file '#{thumb_file}' detected", logfile)
|
||||
|
||||
# Get the base name of the thumbnail file without its extension
|
||||
base_name = File.basename(thumb_file, File.extname(thumb_file))
|
||||
|
||||
model_file = nil # Initialize model_file to nil
|
||||
|
||||
# Loop over the list of extensions
|
||||
XRForge::MODEL_EXT.each do |ext|
|
||||
# Construct the filename with the current extension
|
||||
filename = "#{base_name}#{ext}"
|
||||
|
||||
# Check if the file exists
|
||||
if File.exist?(filename)
|
||||
XRForge.log("✅ 3D file '#{filename}' detected", logfile)
|
||||
model_file = "#{dir.gsub("/mnt/","")}/#{filename}" # Store the found filename
|
||||
break # Stop the loop once a file is found
|
||||
# Extract the desired field (assuming the field is named 'model_file')
|
||||
thumb_file = data['image']
|
||||
|
||||
XRForge.log("✅ thumbnail sidecar-file '#{thumb_file}' detected", logfile)
|
||||
|
||||
# Get the base name of the thumbnail file without its extension
|
||||
base_name = File.basename(thumb_file, File.extname(thumb_file))
|
||||
|
||||
model_file = nil # Initialize model_file to nil
|
||||
|
||||
# Loop over the list of extensions
|
||||
XRForge::MODEL_EXT.each do |ext|
|
||||
# Construct the filename with the current extension
|
||||
filename = "#{base_name}#{ext}"
|
||||
|
||||
# Check if the file exists
|
||||
if File.exist?(filename)
|
||||
XRForge.log("✅ 3D file '#{filename}' detected", logfile)
|
||||
model_file = "#{dir.gsub("/mnt/","")}/#{filename}" # Store the found filename
|
||||
break # Stop the loop once a file is found
|
||||
else
|
||||
# Log a message for the file that was not found, but don't stop
|
||||
XRForge.log("⚠️ 3D file '#{filename}' not detected", logfile)
|
||||
end
|
||||
end
|
||||
|
||||
# Check if a model file was found after the loop
|
||||
if model_file
|
||||
XRForge.log("✅ Final model file: '#{model_file}'", logfile)
|
||||
else
|
||||
# Log a message for the file that was not found, but don't stop
|
||||
XRForge.log("⚠️ 3D file '#{filename}' not detected", logfile)
|
||||
XRForge.log("❌ No suitable 3D file found for XR Fragments- / JanusXR-compatible experience", logfile)
|
||||
end
|
||||
|
||||
# Get the value of the environment variable FEDERATE_DRIVE_HOST
|
||||
federate_drive_host = ENV['FEDERATE_DRIVE_HOST']
|
||||
|
||||
# Define the HTML content using a multi-line string (heredoc)
|
||||
# Ruby's heredoc allows for variable interpolation (using #{})
|
||||
jml = <<~JML
|
||||
<FireBoxRoom>
|
||||
<Assets>
|
||||
<assetobject id="experience" src="#{federate_drive_host}/#{model_file.gsub("#","%23")}"/>
|
||||
</Assets>
|
||||
<Room>
|
||||
<object pos="0 0 0" collision_id="experience" id="experience" />
|
||||
</Room>
|
||||
</FireBoxRoom>
|
||||
JML
|
||||
|
||||
html = <<~HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>janusxr room</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://web.janusvr.com/janusweb.js"></script>
|
||||
<janus-viewer>
|
||||
#{jml}
|
||||
</janus-viewer>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
File.write('.xrforge/janusxr.html', html)
|
||||
File.write('.xrforge/scene.jml', jml)
|
||||
|
||||
XRForge.log("✅ generated scene.jml", logfile)
|
||||
XRForge.log("✅ generated janusxr.html", logfile)
|
||||
XRForge.log(" ", logfile)
|
||||
|
||||
# tag it!
|
||||
if ! data['keywords'].include?('janusxr')
|
||||
data['keywords'].push('janusxr')
|
||||
File.write(file_path, JSON.pretty_generate(data) )
|
||||
end
|
||||
end
|
||||
|
||||
# Check if a model file was found after the loop
|
||||
if model_file
|
||||
XRForge.log("✅ Final model file: '#{model_file}'", logfile)
|
||||
else
|
||||
XRForge.log("❌ No suitable 3D file found for XR Fragments- / JanusXR-compatible experience", logfile)
|
||||
end
|
||||
|
||||
# Get the value of the environment variable FEDERATE_DRIVE_HOST
|
||||
federate_drive_host = ENV['FEDERATE_DRIVE_HOST']
|
||||
|
||||
# Define the HTML content using a multi-line string (heredoc)
|
||||
# Ruby's heredoc allows for variable interpolation (using #{})
|
||||
jml = <<~HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>janusxr room</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://web.janusvr.com/janusweb.js"></script>
|
||||
<janus-viewer>
|
||||
<FireBoxRoom>
|
||||
<Assets>
|
||||
<assetobject id="experience" src="#{federate_drive_host}/#{model_file.gsub("#","%23")}"/>
|
||||
</Assets>
|
||||
<Room>
|
||||
<object pos="0 0 0" collision_id="experience" id="experience" />
|
||||
</Room>
|
||||
</FireBoxRoom>
|
||||
</janus-viewer>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
# Write the content to the specified file
|
||||
# File.write is the concise equivalent of 'echo "$jml" > filename'
|
||||
File.write('.xrforge/janusxr.html', jml)
|
||||
|
||||
XRForge.log("✅ written janusxr.html", logfile)
|
||||
|
||||
XRForge.log(" ", logfile)
|
||||
|
||||
rescue Errno::ENOENT
|
||||
puts "File #{filename} not found"
|
||||
|
|
|
|||
87
manyfold/root/hook.d/experience_updated/300-package_mml.rb
Executable file
87
manyfold/root/hook.d/experience_updated/300-package_mml.rb
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'json'
|
||||
require_relative './../../xrforge.rb'
|
||||
|
||||
# Check if a filename is provided
|
||||
if ARGV.length != 1
|
||||
puts "Usage: #{$0} <path/to/experience/somefile.xxx>"
|
||||
exit 1
|
||||
end
|
||||
|
||||
filename = ARGV[0]
|
||||
|
||||
begin
|
||||
|
||||
# Change the directory
|
||||
dir = File.dirname(filename)
|
||||
Dir.chdir( File.dirname(filename) )
|
||||
# Read and parse the JSON file
|
||||
data = JSON.parse( File.read( "datapackage.json" ) )
|
||||
|
||||
if data['keywords'].empty? || data['keywords'].include?('mml')
|
||||
|
||||
logfile = File.join( File.dirname(filename), ".xrforge/log.txt" )
|
||||
|
||||
XRForge.log("✅ starting build mml XR scene", logfile)
|
||||
|
||||
# Extract the desired field (assuming the field is named 'model_file')
|
||||
thumb_file = data['image']
|
||||
|
||||
XRForge.log("✅ thumbnail sidecar-file '#{thumb_file}' detected", logfile)
|
||||
|
||||
# Get the base name of the thumbnail file without its extension
|
||||
base_name = File.basename(thumb_file, File.extname(thumb_file))
|
||||
|
||||
model_file = nil # Initialize model_file to nil
|
||||
|
||||
# Loop over the list of extensions
|
||||
XRForge::MODEL_EXT.each do |ext|
|
||||
# Construct the filename with the current extension
|
||||
filename = "#{base_name}#{ext}"
|
||||
|
||||
# Check if the file exists
|
||||
if File.exist?(filename)
|
||||
XRForge.log("✅ 3D file '#{filename}' detected", logfile)
|
||||
model_file = "#{dir.gsub("/mnt/","")}/#{filename}" # Store the found filename
|
||||
break # Stop the loop once a file is found
|
||||
else
|
||||
# Log a message for the file that was not found, but don't stop
|
||||
XRForge.log("⚠️ 3D file '#{filename}' not detected", logfile)
|
||||
end
|
||||
end
|
||||
|
||||
# Check if a model file was found after the loop
|
||||
if model_file
|
||||
XRForge.log("✅ Final model file: '#{model_file}'", logfile)
|
||||
else
|
||||
XRForge.log("❌ No suitable 3D file found for XR Fragments- / MML-compatible experience", logfile)
|
||||
end
|
||||
|
||||
# Get the value of the environment variable FEDERATE_DRIVE_HOST
|
||||
federate_drive_host = ENV['FEDERATE_DRIVE_HOST']
|
||||
|
||||
# https://viewer.mml.io/main/v1/?url=https%3A%2F%2Ffoo.org%2Fbar.mml
|
||||
mml = <<~MML
|
||||
<m-model src="#{federate_drive_host}/#{model_file.gsub("#","%23")}" anim-loop="true" anim-enabled="true"></m-model>
|
||||
MML
|
||||
|
||||
File.write('.xrforge/scene.mml', mml)
|
||||
|
||||
XRForge.log("✅ generated scene.mml", logfile)
|
||||
XRForge.log(" ", logfile)
|
||||
|
||||
# tag it!
|
||||
if ! data['keywords'].include?('mml')
|
||||
data['keywords'].push('mml')
|
||||
File.write(file_path, JSON.pretty_generate(data) )
|
||||
end
|
||||
end
|
||||
|
||||
rescue Errno::ENOENT
|
||||
puts "File #{filename} not found"
|
||||
rescue JSON::ParserError
|
||||
puts "Error parsing JSON from #{filename}"
|
||||
rescue => e
|
||||
puts "An error occurred: #{e.message}"
|
||||
end
|
||||
32
manyfold/usr/src/app/app/views/models/_tags_info.html.erb
Normal file
32
manyfold/usr/src/app/app/views/models/_tags_info.html.erb
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
Features can be toggled via tags:<br>
|
||||
<br>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td>
|
||||
<a class="badge rounded-pill bg-secondary tag">menu</a>
|
||||
</td>
|
||||
<td>
|
||||
This will generate a navigator-menu <b>into</b> your main 3D file.<br>
|
||||
The links can be edited <%= link_to "here", edit_model_path(@model) %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a class="badge rounded-pill bg-secondary tag">janusxr</a>
|
||||
</td>
|
||||
<td>
|
||||
This generates an JanusXR address.<br>
|
||||
<a href="https://janusxr.org/" target="_blank">JanusXR</a> is an Open Immersive Web-layer since 2015, which allows existing webpages to become spatial.<br>
|
||||
It is Free and Opensource, and allows you to meet others in this experience (avatars, chat and voice etc).<br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a class="badge rounded-pill bg-secondary tag">mml</a>
|
||||
</td>
|
||||
<td>
|
||||
This generates an MML address.<br>
|
||||
Metaverse Markup Language (<a href="https://mml.io" target="_blank">MML</a>) is an open markup language used to define experiences.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
@ -1,298 +1,338 @@
|
|||
<% content_for :head do %>
|
||||
<%= tag.meta property: "og:type", content: "website" %>
|
||||
<%= tag.meta property: "og:image", content: model_model_file_url(@model, @model.preview_file, format: @model.preview_file.extension) if @model.preview_file&.is_image? && !@model.sensitive %>
|
||||
<%= tag.meta name: "description", content: truncate(sanitize(@model.notes), length: 80) if @model.notes.present? %>
|
||||
<%= tag.meta name: "fediverse:creator", content: @model.creator.federails_actor.at_address if @model.creator %>
|
||||
<%= tag.link rel: "alternate", type: Mime[:oembed], href: model_url(@model, format: :oembed), title: @model.name %>
|
||||
<% end %>
|
||||
|
||||
<div itemscope itemtype="https://schema.org/3DModel">
|
||||
<%= turbo_stream_from @model %>
|
||||
<h1>
|
||||
<span itemprop="name">
|
||||
<a contenteditable="plaintext-only"
|
||||
data-controller="editable"
|
||||
data-action="focus->editable#onFocus blur->editable#onBlur"
|
||||
data-editable-field="model[name]"
|
||||
data-editable-path="<%= model_path(@model) %>"><%= @model.name %></a>
|
||||
</span>
|
||||
<%= link_to icon("search", t(".search")),
|
||||
"https://yeggi.com/q/#{ERB::Util.url_encode(@model.name)}/",
|
||||
class: "btn btn-outline", target: "manyfold_search", rel: "noreferrer" %>
|
||||
</h1>
|
||||
|
||||
<div class="row row-cols-md-2 mt-2">
|
||||
<div class="col-md-9" id="item_list">
|
||||
<% if @locked_files > 0 %>
|
||||
<div class="alert alert-info"><%= t(".preview", count: @locked_files) %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "image_carousel", images: @images %>
|
||||
|
||||
<%= card(:secondary) do %>
|
||||
<p class="card-text" itemprop="description"><%= markdownify @model.notes %></p>
|
||||
<% end if @model.notes.present? %>
|
||||
|
||||
<% if @num_files > 0 %>
|
||||
<h2><a name="files"><%= t(".files") %></a></h2>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 mb-4">
|
||||
<%= render partial: "file", collection: @groups.delete(nil) %>
|
||||
</div>
|
||||
<% @groups.each_pair do |group, files| %>
|
||||
<h3><a name="<%= group.parameterize %>"><%= group.strip.careful_titleize %>*</a></h3>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 mb-4">
|
||||
<%= render partial: "file", collection: files %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-md-3" id="sidebar">
|
||||
<%= card :secondary, t(".model_details") do %>
|
||||
<table class="table table-borderless table-sm">
|
||||
<% if SiteSettings.federation_enabled? %>
|
||||
<tr>
|
||||
<td>⁂</td>
|
||||
<td><% if @model.remote? %>
|
||||
<small><%= link_to @model.federails_actor.at_address, @model.federails_actor.profile_url, target: "new" %></small>
|
||||
<% else %>
|
||||
<small>
|
||||
<%= @model.federails_actor.short_at_address %>
|
||||
<%= render Components::CopyButton.new(text: @model.federails_actor.at_address) %>
|
||||
</small>
|
||||
<% end %>
|
||||
<label for="toggle_activitypub"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_activitypub" hidden>
|
||||
<div class="hidden-tooltip">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is the <a href="https://en.wikipedia.org/wiki/Fediverse" target="_blank">fediverse</a> activitypub address of this experience.<br>
|
||||
Follow updates by copy/pasting it into ActivityPub <a href="https://codeberg.org/fediverse/delightful-fediverse-clients" target="_blank">clients</a>.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @model.creator %>
|
||||
<tr>
|
||||
<td><%= icon "person", Creator.model_name.human %></td>
|
||||
<td><%= link_to @model.creator.name, @model.creator, itemprop: "author" %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if ENV['FEDERATE_DRIVE_HOST'].present? %>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-people" role="img"></i>
|
||||
</td>
|
||||
<td>
|
||||
<%= link_to "JanusXR Metaverse", ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/janusxr.html" %>
|
||||
<label for="toggle_janusxr"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_janusxr" hidden>
|
||||
<div class="hidden-tooltip">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is the JanusXR address.<br>
|
||||
<a href="https://janusxr.org/" target="_blank">JanusXR</a> is an established Metaverse since 2015.<br>
|
||||
It is Free and Opensource, and allows you to meet others in this experience (avatars, chat and voice etc).
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-file-zip" role="img"></i>
|
||||
</td>
|
||||
<td><%= link_to "zip archive", "/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/experience.zip" %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-journal-check" role="img"></i>
|
||||
</td>
|
||||
<td>
|
||||
<%= link_to "build log", ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/log.txt", target: "_blank" %>
|
||||
<label for="toggle_log"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_log" hidden>
|
||||
<div class="hidden-tooltip" style="max-height:400px">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is the build log of XR Forge.<br>
|
||||
When you add files, they are processed, validated (for <a href="https://xrfragment.org" target="_blank">XR Fragment</a> compliance).<br>
|
||||
But also features can be toggled via tags:<br>
|
||||
<br>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td>
|
||||
<a class="badge rounded-pill bg-secondary tag">menu</a>
|
||||
</td>
|
||||
<td>
|
||||
This will generate a navigator-menu <b>into</b> your main 3D file.<br>
|
||||
The links can be edited <%= link_to "here", edit_model_path(@model) %>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-controller" role="img"></i>
|
||||
</td>
|
||||
<td>
|
||||
<%= link_to "Godot project", ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/godot.zip" %>
|
||||
<label for="toggle_godot"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_godot" hidden>
|
||||
<div class="hidden-tooltip">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is a Godot project which wraps your (3D file) experience.<br>
|
||||
<a href="https://godot.org" target="_blank">Godot</a> is a Free and Opensource Game engine.<br>
|
||||
The Godot project is basically its own XR Fragment browser (which you can extend).<br><br>
|
||||
<b>WARNING</b>: use <a href="https://en.wikipedia.org/wiki/Progressive_enhancement" target="_blank">progressive enhancement</a> so your 3D file experience will always run in other <a href="https://xrfragment.org" target="_blank">XR Fragment</a> viewers.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% content_for :head do %>
|
||||
<%= tag.meta property: "og:type", content: "website" %>
|
||||
<%= tag.meta property: "og:image", content: model_model_file_url(@model, @model.preview_file, format: @model.preview_file.extension) if @model.preview_file&.is_image? && !@model.sensitive %>
|
||||
<%= tag.meta name: "description", content: truncate(sanitize(@model.notes), length: 80) if @model.notes.present? %>
|
||||
<%= tag.meta name: "fediverse:creator", content: @model.creator.federails_actor.at_address if @model.creator %>
|
||||
<%= tag.link rel: "alternate", type: Mime[:oembed], href: model_url(@model, format: :oembed), title: @model.name %>
|
||||
<% end %>
|
||||
|
||||
<div itemscope itemtype="https://schema.org/3DModel">
|
||||
<%= turbo_stream_from @model %>
|
||||
<h1>
|
||||
<span itemprop="name">
|
||||
<a contenteditable="plaintext-only"
|
||||
data-controller="editable"
|
||||
data-action="focus->editable#onFocus blur->editable#onBlur"
|
||||
data-editable-field="model[name]"
|
||||
data-editable-path="<%= model_path(@model) %>"><%= @model.name %></a>
|
||||
</span>
|
||||
<%= link_to icon("search", t(".search")),
|
||||
"https://yeggi.com/q/#{ERB::Util.url_encode(@model.name)}/",
|
||||
class: "btn btn-outline", target: "manyfold_search", rel: "noreferrer" %>
|
||||
</h1>
|
||||
|
||||
<div class="row row-cols-md-2 mt-2">
|
||||
<div class="col-md-9" id="item_list">
|
||||
<% if @locked_files > 0 %>
|
||||
<div class="alert alert-info"><%= t(".preview", count: @locked_files) %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "image_carousel", images: @images %>
|
||||
|
||||
<%= card(:secondary) do %>
|
||||
<p class="card-text" itemprop="description"><%= markdownify @model.notes %></p>
|
||||
<% end if @model.notes.present? %>
|
||||
|
||||
<% if @num_files > 0 %>
|
||||
<h2><a name="files"><%= t(".files") %></a></h2>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 mb-4">
|
||||
<%= render partial: "file", collection: @groups.delete(nil) %>
|
||||
</div>
|
||||
<% @groups.each_pair do |group, files| %>
|
||||
<h3><a name="<%= group.parameterize %>"><%= group.strip.careful_titleize %>*</a></h3>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 mb-4">
|
||||
<%= render partial: "file", collection: files %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-md-3" id="sidebar">
|
||||
<%= card :secondary, t(".model_details") do %>
|
||||
<table class="table table-borderless table-sm">
|
||||
<% if SiteSettings.federation_enabled? %>
|
||||
<tr>
|
||||
<td>⁂</td>
|
||||
<td><% if @model.remote? %>
|
||||
<small><%= link_to @model.federails_actor.at_address, @model.federails_actor.profile_url, target: "new" %></small>
|
||||
<% else %>
|
||||
<small>
|
||||
<%= @model.federails_actor.short_at_address %>
|
||||
<%= render Components::CopyButton.new(text: @model.federails_actor.at_address) %>
|
||||
</small>
|
||||
<% end %>
|
||||
<label for="toggle_activitypub"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_activitypub" hidden>
|
||||
<div class="hidden-tooltip">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is the <a href="https://en.wikipedia.org/wiki/Fediverse" target="_blank">fediverse</a> activitypub address of this experience.<br>
|
||||
Follow updates by copy/pasting it into ActivityPub <a href="https://codeberg.org/fediverse/delightful-fediverse-clients" target="_blank">clients</a>.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @model.collection %>
|
||||
<tr>
|
||||
<td><%= icon "collection", Collection.model_name.human(count: 100) %></td>
|
||||
<td><%= link_to @model.collection.name, models_path({collection: @model.collection}.merge(@filter&.to_params)) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if SiteSettings.show_libraries || current_user&.is_administrator? %>
|
||||
<tr>
|
||||
<td><%= icon "boxes", Library.model_name.human %></td>
|
||||
<td><%= link_to @model.library.name, models_path({library: @model.library}.merge(@filter&.to_params)) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @model.license %>
|
||||
<tr>
|
||||
<td><%= icon "card-heading", t(".license") %></td>
|
||||
<td>
|
||||
<%= Spdx.licenses[@model.license]&.fetch("reference") ?
|
||||
link_to(t_license(@model.license), Spdx.licenses[@model.license]["reference"], itemprop: "license") :
|
||||
t_license(@model.license) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @model.sensitive %>
|
||||
<tr>
|
||||
<td><%= icon("explicit", Model.human_attribute_name(:sensitive)) %></td>
|
||||
<td>
|
||||
<%= Model.human_attribute_name(:sensitive) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<tr>
|
||||
<td><%= icon "folder", t(".path") %></td>
|
||||
<td>
|
||||
<%= content_tag(:code, class: "path") { safe_join @model.path.split("/"), safe_join([tag.wbr, "/"]) } %>
|
||||
<% unless @model.contains_other_models? %>
|
||||
<div><%= button_tag(t(".organize.button_text"), class: "btn btn-warning btn-sm", "data-bs-toggle": "modal", "data-bs-target": "#confirm-move") if @model.needs_organizing? && policy(@model).edit? %></div>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= icon "tag", t(".tags") %></td>
|
||||
<td><%= render "tag_list", tags: @model.tags.order(taggings_count: :desc, name: :asc), filter: @filter %></td>
|
||||
</tr>
|
||||
<% if SiteSettings.social_enabled? %>
|
||||
<tr>
|
||||
<td><%= icon "people", t(".followers") %></td>
|
||||
<td><%= t("general.followers", count: @model.followers.count) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<tr>
|
||||
<td><%= render Components::AccessIndicator.new(object: @model, text: false) %></td>
|
||||
<td><%= render Components::AccessIndicator.new(object: @model, text: true, icon: false) %></td>
|
||||
</tr>
|
||||
</table>
|
||||
<%= render Components::FollowButton.new(follower: current_user, target: @model) unless @model.remote? %>
|
||||
<%= render Components::GoButton.new(icon: "pencil", label: t("general.edit"), href: edit_model_path(@model), variant: "primary") if policy(@model).edit? %>
|
||||
<%= render Components::DoButton.new(icon: "trash", label: t("general.delete"), href: model_path(@model), method: :delete, variant: "outline-danger", confirm: translate("models.destroy.confirm")) if policy(@model).destroy? %>
|
||||
<% end %>
|
||||
|
||||
<div class="mb-3 w-100 text-center">
|
||||
<%= render Components::DownloadButton.new(model: @model) %>
|
||||
</div>
|
||||
|
||||
<%= card :secondary, t("layouts.card_list_page.actions_heading") do %>
|
||||
<%= render Components::ReportButton.new(object: @model, path: new_model_report_path(@model)) %>
|
||||
<% end if SiteSettings.multiuser_enabled? %>
|
||||
|
||||
<% if !@model.parents.empty? && policy(@model).merge? %>
|
||||
<%= card :danger, t(".merge.heading") do %>
|
||||
<p>
|
||||
<%= t(".merge.warning") %>
|
||||
</p>
|
||||
<strong><%= t(".merge.with") %>:</strong>
|
||||
<% @model.parents.each do |parent| %>
|
||||
<%= render Components::DoButton.new(icon: "union", label: parent.name, href: merge_models_path(target: parent.public_id, models: [@model.public_id]), method: :post, variant: "danger") %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= render partial: "problem", collection: @model.problems.visible(problem_settings) %>
|
||||
|
||||
<%= card :secondary, t(".files_card.heading") do %>
|
||||
<a href="#files">Top</a>
|
||||
<ul>
|
||||
<% @groups.each_pair do |group, files| %>
|
||||
<li><a href="#<%= group.parameterize %>"><%= group.strip.careful_titleize %>*</a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<%= link_to t(".files_card.bulk_edit"), bulk_edit_model_model_files_path(@model), class: "btn btn-secondary" if policy(@model).edit? %>
|
||||
<%= link_to t(".rescan"), scan_model_path(@model), class: "btn btn-warning", method: :post if policy(@model).scan? %>
|
||||
<% end %>
|
||||
|
||||
<%= render "links_card", links: @model.links %>
|
||||
|
||||
<div class="modal fade" id="confirm-move" data-bs-backdrop='static' tabindex="-1" aria-labelledby="confirmMoveLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title" id="confirmMoveLabel"><%= t(".organize.button_text") %></div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
<%= t(".organize.confirm.summary_html", from: @model.path, to: @model.formatted_path) %>
|
||||
</p>
|
||||
<p>
|
||||
<%= t(".organize.confirm.are_you_sure") %>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><%= t(".organize.confirm.no") %></button>
|
||||
<%= button_to t(".organize.confirm.yes"), model_path(@model, "model[organize]": true), method: :patch, class: "btn btn-warning" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if policy(@model).upload? %>
|
||||
<%= card :warning, t(".upload_card.heading") do %>
|
||||
<%= form_with url: model_model_files_path(@model), id: "upload-form", class: "d-grid" do |form| %>
|
||||
|
||||
<%= content_tag :div, nil, class: "mb-3", data: {
|
||||
controller: "upload",
|
||||
action: "turbo:morph@window->upload#reconnect",
|
||||
max_file_size: SiteSettings.max_file_upload_size,
|
||||
allowed_file_types: input_accept_string,
|
||||
upload_endpoint: upload_path
|
||||
} %>
|
||||
<%= submit_tag translate(".submit"), class: "btn btn-primary d-block" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% if @model.creator %>
|
||||
<tr>
|
||||
<td><%= icon "person", Creator.model_name.human %></td>
|
||||
<td><%= link_to @model.creator.name, @model.creator, itemprop: "author" %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if ENV['FEDERATE_DRIVE_HOST'].present? %>
|
||||
|
||||
<% if @model.tags.where(name: "janusxr" ).any? %>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-eye-fill" role="img"></i>
|
||||
</td>
|
||||
<td>
|
||||
<%
|
||||
fediURL = ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/janusxr.html"
|
||||
%>
|
||||
<%= link_to "JanusXR address", fediURL, target:"_blank" %>
|
||||
<a href="" target="_blank"><i class="bi bi-link-45deg"></i></a>
|
||||
<label for="toggle_janusxr"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_janusxr" hidden>
|
||||
<div class="hidden-tooltip">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is the JanusXR address.<br>
|
||||
<a href="https://janusxr.org/" target="_blank">JanusXR</a> is an Open Immersive Web-layer since 2015, which allows existing webpages to become spatial.<br>
|
||||
It is Free and Opensource, and allows you to meet others in this experience (avatars, chat and voice etc).<br>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<%
|
||||
# lets generate a JanusXR spatial layer for the current scene
|
||||
jmlfile = @model.library.path+"/"+@model.path+"/.xrforge/scene.jml"
|
||||
jml = ""
|
||||
if File.exist?(jmlfile)
|
||||
jml = File.read(jmlfile)
|
||||
end
|
||||
%>
|
||||
|
||||
<!-- JML (https://janusxr.org) spatial markup
|
||||
|
||||
<%== jml %>
|
||||
-->
|
||||
|
||||
<% end %>
|
||||
|
||||
<% if @model.tags.where(name: "mml" ).any? %>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-eye-fill" role="img"></i>
|
||||
</td>
|
||||
<td>
|
||||
<%= link_to "MML address", "https://viewer.mml.io/main/v1/?url="+URI.encode_www_form_component(ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/scene.mml"), target:"_blank" %>
|
||||
<a href="<%= ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/scene.mml" %>" target="_blank"><i class="bi bi-link-45deg"></i></a>
|
||||
<label for="toggle_mml"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_mml" hidden>
|
||||
<div class="hidden-tooltip">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is the MML address.<br>
|
||||
Metaverse Markup Language (<a href="https://mml.io" target="_blank">MML</a>) is an open markup language used to define experiences.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-journal-check" role="img"></i>
|
||||
</td>
|
||||
<td>
|
||||
<%= link_to "build log", ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/log.txt", target: "_blank" %>
|
||||
<label for="toggle_log"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_log" hidden>
|
||||
<div class="hidden-tooltip" style="max-height:400px">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is the build log of XR Forge.<br>
|
||||
When you add files, they are processed, validated (for <a href="https://xrfragment.org" target="_blank">XR Fragment</a> compliance).<br>
|
||||
<% render 'models/tags_info' %>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi bi-controller" role="img"></i>
|
||||
</td>
|
||||
<td>
|
||||
<%= link_to "Godot project", ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/godot.zip" %>
|
||||
<label for="toggle_godot"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_godot" hidden>
|
||||
<div class="hidden-tooltip">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
This is a Godot project which wraps your (3D file) experience.<br>
|
||||
<a href="https://godot.org" target="_blank">Godot</a> is a Free and Opensource Game engine.<br>
|
||||
The Godot project is basically its own XR Fragment browser (which you can extend).<br><br>
|
||||
<b>WARNING</b>: use <a href="https://en.wikipedia.org/wiki/Progressive_enhancement" target="_blank">progressive enhancement</a> so your 3D file experience will always run in other <a href="https://xrfragment.org" target="_blank">XR Fragment</a> viewers.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
<% if @model.collection %>
|
||||
<tr>
|
||||
<td><%= icon "collection", Collection.model_name.human(count: 100) %></td>
|
||||
<td><%= link_to @model.collection.name, models_path({collection: @model.collection}.merge(@filter&.to_params)) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if SiteSettings.show_libraries || current_user&.is_administrator? %>
|
||||
<tr>
|
||||
<td><%= icon "boxes", Library.model_name.human %></td>
|
||||
<td><%= link_to @model.library.name, models_path({library: @model.library}.merge(@filter&.to_params)) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @model.license %>
|
||||
<tr>
|
||||
<td><%= icon "card-heading", t(".license") %></td>
|
||||
<td>
|
||||
<%= Spdx.licenses[@model.license]&.fetch("reference") ?
|
||||
link_to(t_license(@model.license), Spdx.licenses[@model.license]["reference"], itemprop: "license") :
|
||||
t_license(@model.license) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @model.sensitive %>
|
||||
<tr>
|
||||
<td><%= icon("explicit", Model.human_attribute_name(:sensitive)) %></td>
|
||||
<td>
|
||||
<%= Model.human_attribute_name(:sensitive) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<tr>
|
||||
<td><%= icon "folder", t(".path") %></td>
|
||||
<td>
|
||||
<%= content_tag(:code, class: "path") { safe_join @model.path.split("/"), safe_join([tag.wbr, "/"]) } %>
|
||||
<% unless @model.contains_other_models? %>
|
||||
<div><%= button_tag(t(".organize.button_text"), class: "btn btn-warning btn-sm", "data-bs-toggle": "modal", "data-bs-target": "#confirm-move") if @model.needs_organizing? && policy(@model).edit? %></div>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= icon "tag", t(".tags") %></td>
|
||||
<td><%= render "tag_list", tags: @model.tags.order(taggings_count: :desc, name: :asc), filter: @filter %>
|
||||
<label for="toggle_tags"><i class="bi bi-info-circle"></i></label>
|
||||
<div class="toggle-box">
|
||||
<input type="checkbox" id="toggle_tags" hidden>
|
||||
<div class="hidden-tooltip" style="max-height:400px">
|
||||
<i class="bi bi-arrow-90deg-up"></i>
|
||||
<small>
|
||||
<% render 'models/tags_info' %>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% if SiteSettings.social_enabled? %>
|
||||
<tr>
|
||||
<td><%= icon "people", t(".followers") %></td>
|
||||
<td><%= t("general.followers", count: @model.followers.count) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<tr>
|
||||
<td><%= render Components::AccessIndicator.new(object: @model, text: false) %></td>
|
||||
<td><%= render Components::AccessIndicator.new(object: @model, text: true, icon: false) %></td>
|
||||
</tr>
|
||||
</table>
|
||||
<%= render Components::FollowButton.new(follower: current_user, target: @model) unless @model.remote? %>
|
||||
<%= render Components::GoButton.new(icon: "pencil", label: t("general.edit"), href: edit_model_path(@model), variant: "primary") if policy(@model).edit? %>
|
||||
<%= render Components::DoButton.new(icon: "trash", label: t("general.delete"), href: model_path(@model), method: :delete, variant: "outline-danger", confirm: translate("models.destroy.confirm")) if policy(@model).destroy? %>
|
||||
<% end %>
|
||||
|
||||
<div class="mb-3 w-100 text-center">
|
||||
<%= render Components::DownloadButton.new(model: @model) %>
|
||||
</div>
|
||||
|
||||
<%= card :secondary, t("layouts.card_list_page.actions_heading") do %>
|
||||
<%= render Components::ReportButton.new(object: @model, path: new_model_report_path(@model)) %>
|
||||
<% end if SiteSettings.multiuser_enabled? %>
|
||||
|
||||
<% if !@model.parents.empty? && policy(@model).merge? %>
|
||||
<%= card :danger, t(".merge.heading") do %>
|
||||
<p>
|
||||
<%= t(".merge.warning") %>
|
||||
</p>
|
||||
<strong><%= t(".merge.with") %>:</strong>
|
||||
<% @model.parents.each do |parent| %>
|
||||
<%= render Components::DoButton.new(icon: "union", label: parent.name, href: merge_models_path(target: parent.public_id, models: [@model.public_id]), method: :post, variant: "danger") %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= render partial: "problem", collection: @model.problems.visible(problem_settings) %>
|
||||
|
||||
<%= card :secondary, t(".files_card.heading") do %>
|
||||
<a href="#files">Top</a>
|
||||
<ul>
|
||||
<% @groups.each_pair do |group, files| %>
|
||||
<li><a href="#<%= group.parameterize %>"><%= group.strip.careful_titleize %>*</a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<%= link_to t(".files_card.bulk_edit"), bulk_edit_model_model_files_path(@model), class: "btn btn-secondary" if policy(@model).edit? %>
|
||||
<%= link_to t(".rescan"), scan_model_path(@model), class: "btn btn-warning", method: :post if policy(@model).scan? %>
|
||||
<% end %>
|
||||
|
||||
<%= render "links_card", links: @model.links %>
|
||||
|
||||
<div class="modal fade" id="confirm-move" data-bs-backdrop='static' tabindex="-1" aria-labelledby="confirmMoveLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title" id="confirmMoveLabel"><%= t(".organize.button_text") %></div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
<%= t(".organize.confirm.summary_html", from: @model.path, to: @model.formatted_path) %>
|
||||
</p>
|
||||
<p>
|
||||
<%= t(".organize.confirm.are_you_sure") %>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><%= t(".organize.confirm.no") %></button>
|
||||
<%= button_to t(".organize.confirm.yes"), model_path(@model, "model[organize]": true), method: :patch, class: "btn btn-warning" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if policy(@model).upload? %>
|
||||
<%= card :warning, t(".upload_card.heading") do %>
|
||||
<%= form_with url: model_model_files_path(@model), id: "upload-form", class: "d-grid" do |form| %>
|
||||
|
||||
<%= content_tag :div, nil, class: "mb-3", data: {
|
||||
controller: "upload",
|
||||
action: "turbo:morph@window->upload#reconnect",
|
||||
max_file_size: SiteSettings.max_file_upload_size,
|
||||
allowed_file_types: input_accept_string,
|
||||
upload_endpoint: upload_path
|
||||
} %>
|
||||
<%= submit_tag translate(".submit"), class: "btn btn-primary d-block" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
25
manyfold/usr/src/app/bin/docker-entrypoint.sh
Executable file
25
manyfold/usr/src/app/bin/docker-entrypoint.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
if [ -f tmp/pids/server.pid ]; then
|
||||
rm tmp/pids/server.pid
|
||||
fi
|
||||
|
||||
echo "Preparing database..."
|
||||
bundle exec rails db:prepare:with_data
|
||||
|
||||
echo "run boot 'hook'"
|
||||
/manyfold/cli/manyfold.sh hook boot &
|
||||
|
||||
echo "Setting database file ownership (SQLite3 only)..."
|
||||
bundle exec rake db:chown
|
||||
|
||||
echo "Cleaning up old cache files..."
|
||||
bundle exec rake tmp:cache:clear
|
||||
|
||||
echo "Setting temporary directory permissions..."
|
||||
chown -R $PUID:$PGID tmp log
|
||||
|
||||
echo "Launching application..."
|
||||
export RAILS_PORT=$PORT
|
||||
export RAILS_LOG_TO_STDOUT=true
|
||||
exec s6-setuidgid $PUID:$PGID "$@"
|
||||
|
|
@ -40,5 +40,6 @@ Rails.application.config.to_prepare do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ rec
|
|||
pkgs.pkgsStatic.inotify-tools # inotifywait e.g.
|
||||
pkgs.pkgsStatic.zip # inotifywait e.g.
|
||||
pkgs.pkgsStatic.ts # job management
|
||||
pkgs.janus-gateway # webrtc server
|
||||
myAssimp # cli 3D editing/conversion
|
||||
./..
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue