diff --git a/CHANGELOG.md b/CHANGELOG.md index 356bca9b0..f710cf6d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `include_js()` and `include_css()` now work as expected when trying to include multiple files from the same directory. (#2069) +* `include_js()` and `include_css()` now correctly handle file permissions in multi-user settings. (#2061) + ### Deprecations * `ui.update_navs()` has been deprecated in favor of `ui.update_navset()`. (#2047) diff --git a/shiny/ui/_include_helpers.py b/shiny/ui/_include_helpers.py index ca09938c2..c818d5e86 100644 --- a/shiny/ui/_include_helpers.py +++ b/shiny/ui/_include_helpers.py @@ -217,11 +217,11 @@ def maybe_copy_files(path: Path | str, include_files: bool) -> tuple[str, str]: # To avoid unnecessary work when the same file is included multiple times, # use a directory scoped by a hash of the file. - tmpdir = os.path.join(tempfile.gettempdir(), "shiny_include_files", hash) + tmpdir = os.path.join(tempfile.gettempdir(), f"shiny_include_{hash}") path_dest = os.path.join(tmpdir, os.path.basename(path)) # Since the hash/tmpdir should represent all the files in the path's directory, - # we can simply return here + # we can check if it exists to determine if we have a cache hit if os.path.exists(path_dest): return path_dest, hash diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/app.py b/tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/app.py similarity index 100% rename from tests/playwright/shiny/bugs/2061-css-js-inclusion/app.py rename to tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/app.py diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/css/style.css b/tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/css/style.css similarity index 100% rename from tests/playwright/shiny/bugs/2061-css-js-inclusion/css/style.css rename to tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/css/style.css diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/js/customjs.js b/tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/js/customjs.js similarity index 100% rename from tests/playwright/shiny/bugs/2061-css-js-inclusion/js/customjs.js rename to tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/js/customjs.js diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/js/customjs2.js b/tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/js/customjs2.js similarity index 100% rename from tests/playwright/shiny/bugs/2061-css-js-inclusion/js/customjs2.js rename to tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/js/customjs2.js diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/test_css-js-inclusion.py b/tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/test_css-js-inclusion.py similarity index 100% rename from tests/playwright/shiny/bugs/2061-css-js-inclusion/test_css-js-inclusion.py rename to tests/playwright/shiny/bugs/2061-css-js-inclusion/include_files_case/test_css-js-inclusion.py diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/app.py b/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/app.py new file mode 100644 index 000000000..4072ca609 --- /dev/null +++ b/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/app.py @@ -0,0 +1,27 @@ +from pathlib import Path + +from shiny import App, Inputs, Outputs, Session, ui + +js_file = Path(__file__).parent / "customjs.js" +css_file = Path(__file__).parent / "style.css" + +# Define the UI +app_ui = ui.page_fluid( + ui.include_css(css_file, method="link"), + ui.include_js(js_file, method="link"), + ui.h1("Simple Shiny App with External CSS"), + ui.div( + ui.p("This is a simple Shiny app that demonstrates ui.include_css()"), + ui.p("The styling comes from an external CSS file!"), + class_="content", + ), +) + + +# Define the server +def server(input: Inputs, output: Outputs, session: Session): + pass + + +# Create and run the app +app = App(app_ui, server) diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/customjs.js b/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/customjs.js new file mode 100644 index 000000000..4dc8fcc69 --- /dev/null +++ b/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/customjs.js @@ -0,0 +1,4 @@ +const newParagraph = document.createElement('p'); +newParagraph.textContent = 'Heyo!'; +document.body.appendChild(newParagraph); + diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/style.css b/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/style.css new file mode 100644 index 000000000..45086e08f --- /dev/null +++ b/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/style.css @@ -0,0 +1,19 @@ +body { + background-color: #70bfef; + font-family: Arial, sans-serif; +} + +h1 { + color: black; + border-bottom: 2px solid #4682b4; + padding-bottom: 10px; +} + +.content { + margin: 20px; + padding: 15px; + background-color: white; + border-radius: 5px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + diff --git a/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/test_css-js-link.py b/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/test_css-js-link.py new file mode 100644 index 000000000..b144f78f6 --- /dev/null +++ b/tests/playwright/shiny/bugs/2061-css-js-inclusion/not_include_files_case/test_css-js-link.py @@ -0,0 +1,9 @@ +from playwright.sync_api import Page, expect + +from shiny.run import ShinyAppProc + + +def test_inclusion(page: Page, local_app: ShinyAppProc) -> None: + page.goto(local_app.url) + + expect(page.locator("body > p")).to_have_text("Heyo!")