diff --git a/backend/btrixcloud/colls.py b/backend/btrixcloud/colls.py
index 2cf8de71..39f8cf6f 100644
--- a/backend/btrixcloud/colls.py
+++ b/backend/btrixcloud/colls.py
@@ -7,7 +7,7 @@ import uuid
from typing import Optional, List
import pymongo
-from fastapi import Depends, HTTPException
+from fastapi import Depends, HTTPException, Response
from fastapi.responses import StreamingResponse
from .basecrawls import SUCCESSFUL_STATES
@@ -148,10 +148,14 @@ class CollectionOps:
return await self.get_collection(coll_id, org)
async def get_collection(
- self, coll_id: uuid.UUID, org: Organization, resources=False
+ self, coll_id: uuid.UUID, org: Organization, resources=False, public_only=False
):
"""Get collection by id"""
- result = await self.collections.find_one({"_id": coll_id})
+ query = {"_id": coll_id}
+ if public_only:
+ query["isPublic"] = True
+
+ result = await self.collections.find_one(query)
if resources:
result["resources"] = await self.get_collection_crawl_resources(
coll_id, org
@@ -348,6 +352,7 @@ def init_collections_api(app, mdb, crawls, orgs, crawl_manager):
org_crawl_dep = orgs.org_crawl_dep
org_viewer_dep = orgs.org_viewer_dep
+ org_public = orgs.org_public
@app.post("/orgs/{oid}/collections", tags=["collections"])
async def add_collection(
@@ -428,8 +433,36 @@ def init_collections_api(app, mdb, crawls, orgs, crawl_manager):
coll = await colls.get_collection(coll_id, org, resources=True)
if not coll:
raise HTTPException(status_code=404, detail="collection_not_found")
+
return coll
+ @app.get(
+ "/orgs/{oid}/collections/{coll_id}/public/replay.json", tags=["collections"]
+ )
+ async def get_collection_public_replay(
+ response: Response,
+ coll_id: uuid.UUID,
+ org: Organization = Depends(org_public),
+ ):
+ coll = await colls.get_collection(
+ coll_id, org, resources=True, public_only=True
+ )
+ if not coll:
+ raise HTTPException(status_code=404, detail="collection_not_found")
+
+ response.headers["Access-Control-Allow-Origin"] = "*"
+ response.headers["Access-Control-Allow-Headers"] = "*"
+ return coll
+
+ @app.options(
+ "/orgs/{oid}/collections/{coll_id}/public/replay.json", tags=["collections"]
+ )
+ async def get_replay_preflight(response: Response):
+ response.headers["Access-Control-Allow-Methods"] = "GET, HEAD, OPTIONS"
+ response.headers["Access-Control-Allow-Origin"] = "*"
+ response.headers["Access-Control-Allow-Headers"] = "*"
+ return {}
+
@app.patch("/orgs/{oid}/collections/{coll_id}", tags=["collections"])
async def update_collection(
coll_id: uuid.UUID,
diff --git a/backend/btrixcloud/models.py b/backend/btrixcloud/models.py
index c6f07eda..69b005eb 100644
--- a/backend/btrixcloud/models.py
+++ b/backend/btrixcloud/models.py
@@ -465,6 +465,8 @@ class Collection(BaseMongoModel):
# Sorted by count, descending
tags: Optional[List[str]] = []
+ isPublic: Optional[bool] = False
+
# ============================================================================
class CollIn(BaseModel):
@@ -474,6 +476,8 @@ class CollIn(BaseModel):
description: Optional[str]
crawlIds: Optional[List[str]] = []
+ isPublic: Optional[bool] = False
+
# ============================================================================
class CollOut(Collection):
@@ -488,6 +492,7 @@ class UpdateColl(BaseModel):
name: Optional[str]
description: Optional[str]
+ isPublic: Optional[bool]
# ============================================================================
diff --git a/backend/btrixcloud/orgs.py b/backend/btrixcloud/orgs.py
index fa48c7d9..c6f89af1 100644
--- a/backend/btrixcloud/orgs.py
+++ b/backend/btrixcloud/orgs.py
@@ -45,6 +45,7 @@ class OrgOps:
self.org_viewer_dep = None
self.org_crawl_dep = None
self.org_owner_dep = None
+ self.org_public = None
self.invites = invites
@@ -300,6 +301,13 @@ def init_orgs_api(app, mdb, user_manager, invites, user_dep: User):
return org
+ async def org_public(oid: str):
+ org = await ops.get_org_by_id(uuid.UUID(oid))
+ if not org:
+ raise HTTPException(status_code=404, detail="org_not_found")
+
+ return org
+
router = APIRouter(
prefix="/orgs/{oid}",
dependencies=[Depends(org_dep)],
@@ -310,6 +318,7 @@ def init_orgs_api(app, mdb, user_manager, invites, user_dep: User):
ops.org_viewer_dep = org_dep
ops.org_crawl_dep = org_crawl_dep
ops.org_owner_dep = org_owner_dep
+ ops.org_public = org_public
@app.get("/orgs", tags=["organizations"], response_model=PaginatedResponse)
async def get_orgs(
diff --git a/backend/btrixcloud/users.py b/backend/btrixcloud/users.py
index 9cd1b744..6154ba5c 100644
--- a/backend/btrixcloud/users.py
+++ b/backend/btrixcloud/users.py
@@ -402,7 +402,6 @@ def init_users_api(app, user_manager):
}
for org in user_orgs
]
- print(f"user info with orgs: {user_info}", flush=True)
return user_info
@users_router.get("/invite/{token}", tags=["invites"])
diff --git a/frontend/src/pages/org/collection-detail.ts b/frontend/src/pages/org/collection-detail.ts
index dd7347f1..f259f7ba 100644
--- a/frontend/src/pages/org/collection-detail.ts
+++ b/frontend/src/pages/org/collection-detail.ts
@@ -51,6 +51,9 @@ export class CollectionDetail extends LiteElement {
@state()
private isDescriptionExpanded = false;
+ @state()
+ private showEmbedInfo = false;
+
// Use to cancel requests
private getArchivedItemsController: AbortController | null = null;
@@ -89,12 +92,32 @@ export class CollectionDetail extends LiteElement {
render() {
return html`${this.renderHeader()}
- ${this.collection?.name ||
- html`
+
+ ${this.collection?.name ||
+ html`
+
+ ${msg( + html`Embed this collection in another site using these + ReplayWeb.page code snippets.` + )} +
++ ${msg(html`Add the following embed code to your HTML page:`)} +
+${embedCode}
+
+ ${msg(
+ html`Add the following JavaScript to
+ ./replay/sw.js
:`
+ )}
+
${importCode}
+ + ${msg( + html`See + + our embedding guide + for more details.` + )} +
+