### Start/Stop Typing Notifications in Ruby Source: https://context7.com/basecamp/once-campfire/llms.txt Implements server-side logic for typing notification channels within a room. It broadcasts 'start' and 'stop' actions along with user information to the specified room. No external dependencies are required beyond the RoomChannel base class. ```ruby class TypingNotificationsChannel < RoomChannel def start(data) broadcast_to @room, action: :start, user: current_user.slice(:id, :name) end def stop(data) broadcast_to @room, action: :stop, user: current_user.slice(:id, :name) end end ``` -------------------------------- ### Campfire Room Creation (Ruby) Source: https://context7.com/basecamp/once-campfire/llms.txt Provides Ruby code examples for creating different types of rooms in Campfire: open (public), closed (private with members), and direct message rooms. Also shows how to manage member access for closed rooms. ```ruby ```ruby # Create an open room (accessible to all users) open_room = Rooms::Open.create_for( { name: "General Discussion" }, users: current_user ) # Create a closed room with specific members team_members = User.where(id: [1, 2, 3, 5]) closed_room = Rooms::Closed.create_for( { name: "Engineering Team" }, users: team_members ) # Create or find direct message room users = User.where(id: [current_user.id, other_user.id]) dm_room = Rooms::Direct.find_or_create_for(users) # Grant access to additional users (closed rooms only) closed_room.memberships.grant_to([user1, user2, user3]) # Revoke access from users closed_room.memberships.revoke_from([user4, user5]) ``` ``` -------------------------------- ### Campfire Bot Webhook Response Handler (Ruby) Source: https://context7.com/basecamp/once-campfire/llms.txt A Ruby example demonstrating how to create a webhook endpoint in a Rails application to receive and process notifications from Campfire. It parses the JSON payload, processes commands, and returns a text response or an attachment. ```ruby ```ruby # Webhook response handler (bot's webhook endpoint) # app/controllers/webhooks/campfire_controller.rb class Webhooks::CampfireController < ApplicationController skip_before_action :verify_authenticity_token def receive payload = JSON.parse(request.body.read) message_body = payload.dig("message", "body", "plain") reply_path = payload.dig("room", "path") # Process the message and generate response response_text = process_command(message_body) # Return text response (will be posted to the room) render plain: response_text, status: :ok # OR return an attachment # send_file "/path/to/file.png", # type: "image/png", # disposition: "inline" end private def process_command(message) case message.strip when /status/i "All systems operational ✓" when /deploy/i "Deployment initiated..." else "Unknown command. Try 'status' or 'deploy'." end end end ``` ``` -------------------------------- ### Search Messages in Ruby and Bash Source: https://context7.com/basecamp/once-campfire/llms.txt Provides functionality for searching messages across rooms a user has access to. It includes sanitizing search queries, retrieving recent messages, recording search history, and clearing the search history. The Ruby code interacts with the application's data model, while the Bash examples demonstrate how to interact with the search API via HTTP requests. ```ruby # Search messages (GET /searches?q=deployment) query = params[:q]&.gsub(/[^[:word:]]/, " ") # Sanitize query messages = current_user.reachable_messages.search(query).last(100) # Record search for recent searches list current_user.searches.record(query) # Get user's recent searches recent = current_user.searches.ordered # Clear search history current_user.searches.destroy_all ``` ```bash # Search via HTTP API curl -X GET "https://chat.example.com/searches?q=deployment+status" \ -H "Cookie: session_token=abc123..." # Returns HTML page with matching messages # Save a search to history curl -X POST "https://chat.example.com/searches" \ -H "Cookie: session_token=abc123..." \ -d "q=important+keyword" # Clear all saved searches curl -X DELETE "https://chat.example.com/searches/clear" \ -H "Cookie: session_token=abc123..." ``` -------------------------------- ### Subscribe to Typing Notifications (JavaScript) Source: https://context7.com/basecamp/once-campfire/llms.txt Subscribes to real-time typing notifications for a room. Manages the display of typing indicators based on start and stop actions received from the server. ```javascript // Subscribe to typing notifications channel const typingChannel = consumer.subscriptions.create( { channel: "TypingNotificationsChannel", room_id: 123 }, { received(data) { if (data.action === "start") { showTypingIndicator(data.user.name); } else if (data.action === "stop") { hideTypingIndicator(data.user.name); } } } ); // Send typing start notification typingChannel.perform("start", {}); // Send typing stop notification typingChannel.perform("stop", {}); ``` -------------------------------- ### Get Plain Text Message Body Source: https://context7.com/basecamp/once-campfire/llms.txt Retrieves the plain text representation of a message's body, stripping any formatting or markdown. ```ruby # Get plain text representation plain = message.plain_text_body # => "Hello, team! Let\'s discuss the new feature." ``` -------------------------------- ### Create New User Source: https://context7.com/basecamp/once-campfire/llms.txt Creates a new user account with provided details including name, email, password, and bio. New users are automatically added to all open rooms. ```ruby # Create a new user user = User.create!( name: "Alice Smith", email_address: "alice@example.com", password: "secure_password", bio: "Product Designer" ) # User automatically gets membership to all open rooms user.rooms.opens # => [#, ...] ``` -------------------------------- ### Go Back Link (HTML) Source: https://github.com/basecamp/once-campfire/blob/main/public/500.html This HTML snippet represents a navigation link to return to the previous page. It is styled using CSS and designed to be accessible, with a class for screen readers. ```html Go back ``` -------------------------------- ### Create Sound Command Message Source: https://context7.com/basecamp/once-campfire/llms.txt Creates a message that executes a specific command, such as playing a sound. The message body is formatted as a command. ```ruby sound_message = room.messages.create!( body: "/play tada", creator: current_user ) ``` -------------------------------- ### Campfire Bot Authentication and Management (Ruby) Source: https://context7.com/basecamp/once-campfire/llms.txt Demonstrates how to create, authenticate, reset keys for, update, and deactivate bots within the Campfire application. Assumes a Rails environment with a User model supporting bot functionalities. ```ruby ```ruby # Create a new bot with webhook URL bot = User.create_bot!( name: "Deployment Bot", webhook_url: "https://example.com/webhooks/ campfire" ) # Bot key format: "user_id-token" (e.g., "123-5M0aLYwQyBXO") bot_key = bot.bot_key # => "42-5M0aLYwQyBXOXa5Wsz6NZb" # Authenticate a bot using its key authenticated_bot = User.authenticate_bot("42-5M0aLYwQyBXOXa5Wsz6NZb") # Reset bot authentication key (invalidates old key) bot.reset_bot_key new_bot_key = bot.bot_key # Update bot configuration bot.update_bot!( name: "Updated Bot Name", webhook_url: "https://newurl.com/webhook" ) # Deactivate a bot bot.deactivate ``` ``` -------------------------------- ### Register and Manage Push Subscriptions in JavaScript and Ruby Source: https://context7.com/basecamp/once-campfire/llms.txt Enables browser push notifications for new messages and mentions. The JavaScript code handles requesting user permission, subscribing to push notifications, and sending the subscription details to the server. The Ruby code manages the server-side storage and retrieval of these push subscriptions, allowing for registration, listing, and unsubscription. ```javascript // Request notification permission and subscribe async function subscribeToPush() { const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY) }); // Send subscription to server const response = await fetch('/users/me/push_subscriptions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({ push_subscription: { endpoint: subscription.endpoint, p256dh_key: base64Encode(subscription.getKey('p256dh')), auth_key: base64Encode(subscription.getKey('auth')) } }) }); if (response.ok) { console.log('Push subscription registered'); } } function urlBase64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/'); const rawData = window.atob(base64); return Uint8Array.from([...rawData].map(char => char.charCodeAt(0))); } function base64Encode(arrayBuffer) { return btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))); } ``` ```ruby # Server-side push subscription management # Create or update push subscription push_subscription = current_user.push_subscriptions.find_by( endpoint: params[:endpoint] ) if push_subscription push_subscription.touch # Update last_used timestamp else current_user.push_subscriptions.create!( endpoint: params[:endpoint], p256dh_key: params[:p256dh_key], auth_key: params[:auth_key], user_agent: request.user_agent ) end # List user's push subscriptions (manage devices) subscriptions = current_user.push_subscriptions # Unsubscribe (remove device) current_user.push_subscriptions.destroy_by(id: subscription_id) # Logout and remove push subscription if endpoint = params[:push_subscription_endpoint] Push::Subscription.destroy_by( endpoint: endpoint, user_id: current_user.id ) end ``` -------------------------------- ### User Login Authentication Source: https://context7.com/basecamp/once-campfire/llms.txt Authenticates a user using their email address and password. If successful, it creates a new session and sets a secure, permanent session cookie. ```ruby # User login user = User.active.authenticate_by( email_address: "alice@example.com", password: "secure_password" ) if user # Create new session session = user.sessions.start!( user_agent: request.user_agent, ip_address: request.remote_ip ) # Set secure session cookie cookies.signed.permanent[:session_token] = { value: session.token, httponly: true, same_site: :lax } end ``` -------------------------------- ### Query Users Source: https://context7.com/basecamp/once-campfire/llms.txt Retrieves lists of users based on specific criteria. Supports filtering by active status, excluding bots, ordering by name, and searching by name. ```ruby # Query users User.active # Active users only User.without_bots # Exclude bot accounts User.ordered # Alphabetically by name User.filtered_by("alice") # Name search ``` -------------------------------- ### Basic CSS Reset and Body Styles Source: https://github.com/basecamp/once-campfire/blob/main/public/422.html Applies a CSS reset for box-sizing and sets up basic body styles including color variables, dark mode support, font family, and layout using CSS Grid. It ensures a consistent look across different devices and color schemes. ```css *, *::before, *::after { box-sizing: border-box; } body { --lch-black: 0% 0 0; --lch-gray: 75% 0.005 96; --lch-white: 100% 0 0; --color-border: oklch(var(--lch-gray)); --color-bg: oklch(var(--lch-white)); --color-text: oklch(var(--lch-black)); --btn-size: 2.65em; background-color: var(--color-bg); block-size: 100dvh; color: var(--color-text); display: grid; margin: 0; padding: 0; place-items: center; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } @media (prefers-color-scheme: dark) { body { --lch-black: 100% 0 0; --lch-gray: 44.95% 0 0; --lch-white: 0% 0 0; } } ``` -------------------------------- ### Create Message with File Attachment Source: https://context7.com/basecamp/once-campfire/llms.txt Creates a new message that includes a file attachment. Requires the attachment file, an optional body, and the creator. ```ruby message = room.messages.create_with_attachment!( attachment: params[:file], body: "Here\'s the design mockup", creator: current_user ) ``` -------------------------------- ### Resume Existing Session Source: https://context7.com/basecamp/once-campfire/llms.txt Resumes a user's session based on the session token found in the cookies. It updates the session with the current user agent and IP address. ```ruby # Resume existing session if session_token = cookies.signed[:session_token] session = Session.find_by(token: session_token) session&.resume( user_agent: request.user_agent, ip_address: request.remote_ip ) end ``` -------------------------------- ### Bot Integration API Source: https://context7.com/basecamp/once-campfire/llms.txt This section details how to create, authenticate, and manage bots within Campfire, as well as how bots can post messages and receive webhook notifications. ```APIDOC ## Bot Integration API ### Creating and Authenticating Bots Bots are special user accounts that can post messages programmatically and receive webhook notifications when mentioned or messaged directly. #### Creating a Bot Use `User.create_bot!` to create a new bot with a specified name and webhook URL. ```ruby # Create a new bot with webhook URL bot = User.create_bot!( name: "Deployment Bot", webhook_url: "https://example.com/webhooks/campfire" ) ``` #### Bot Key Format Bot keys are used for authentication and follow the format `user_id-token`. ```ruby # Bot key format: "user_id-token" (e.g., "123-5M0aLYwQyBXO") bot_key = bot.bot_key # => "42-5M0aLYwQyBXOXa5Wsz6NZb" ``` #### Authenticating a Bot Authenticate a bot using its unique bot key. ```ruby authenticated_bot = User.authenticate_bot("42-5M0aLYwQyBXO") ``` #### Resetting Bot Key Reset the bot's authentication key, which invalidates the old key. ```ruby # Reset bot authentication key (invalidates old key) bot.reset_bot_key new_bot_key = bot.bot_key ``` #### Updating Bot Configuration Update the bot's name and webhook URL. ```ruby # Update bot configuration bot.update_bot!( name: "Updated Bot Name", webhook_url: "https://newurl.com/webhook" ) ``` #### Deactivating a Bot Deactivate a bot to disable its functionality. ```ruby # Deactivate a bot bot.deactivate ``` ### Posting Messages via Bot API Bots can post text messages, file attachments, or commands to rooms they have access to. #### Method `POST` #### Endpoint `/rooms/:room_id/:bot_key/messages` #### Parameters ##### Path Parameters - **room_id** (integer) - Required - The ID of the room to post the message to. - **bot_key** (string) - Required - The authentication key for the bot. ##### Request Body - **message** (string) - Required - The text content of the message. - **attachment** (file) - Optional - A file attachment to send with the message. #### Request Example (Text Message) ```bash curl -X POST https://chat.example.com/rooms/123/42-5M0aLYwQyBXO/messages \ -H "Content-Type: text/plain" \ -d "Deployment to production completed successfully! ✓" ``` #### Request Example (File Attachment) ```bash curl -X POST https://chat.example.com/rooms/123/42-5M0aLYwQyBXO/messages \ -F "attachment=@/path/to/report.pdf" ``` #### Response Example (Success) ``` 201 Created Location: https://chat.example.com/rooms/123/messages/456 ``` ### Receiving Webhook Notifications When a bot is mentioned or receives a direct message, Campfire sends a webhook POST request with the message details. #### Method `POST` #### Endpoint [Configured `webhook_url` for the bot] #### Request Body (Webhook Payload) ```json { "user": { "id": 7, "name": "Alice Smith" }, "room": { "id": 123, "name": "General", "path": "/rooms/123/42-5M0aLYwQyBXO/messages" }, "message": { "id": 456, "body": { "html": "
@DeploymentBot check status
", "plain": "check status" }, "path": "/rooms/123/@456" } } ``` #### Webhook Response Handler Example ```ruby # app/controllers/webhooks/campfire_controller.rb class Webhooks::CampfireController < ApplicationController skip_before_action :verify_authenticity_token def receive payload = JSON.parse(request.body.read) message_body = payload.dig("message", "body", "plain") reply_path = payload.dig("room", "path") response_text = process_command(message_body) render plain: response_text, status: :ok end private def process_command(message) case message.strip when /status/i "All systems operational ✓" when /deploy/i "Deployment initiated..." else "Unknown command. Try 'status' or 'deploy'." end end end ``` ``` -------------------------------- ### Manage User Involvement in Rooms in Ruby Source: https://context7.com/basecamp/once-campfire/llms.txt Allows control over notification preferences and visibility per room for users. It defines different involvement levels (invisible, nothing, mentions, everything), provides methods to check membership status, update involvement levels, mark rooms as read/unread, and query memberships. It also includes functionality to reset WebSocket connections and handle their closure on membership changes. ```ruby # Membership involvement levels # - invisible: Hidden from room, no notifications # - nothing: Visible but no notifications # - mentions: Notifications only for @mentions # - everything: Notifications for all messages membership = current_user.memberships.find_by(room: room) # Check membership status membership.involved_in_invisible? # => false membership.involved_in_nothing? # => false membership.involved_in_mentions? # => true (default) membership.involved_in_everything? # => false # Update involvement level membership.update!(involvement: "everything") # Mark room as read membership.read membership.unread? # => false # Mark as unread (happens automatically on new messages) membership.update!(unread_at: Time.current) membership.unread? # => true # Query memberships Membership.visible # Not invisible Membership.unread # Has unread messages Membership.without_direct_rooms # Exclude DM rooms Membership.with_ordered_room # Ordered by room name # Disconnect user from all rooms (resets WebSocket connections) user.reset_remote_connections # Close WebSocket connections on membership changes # (automatically triggered on membership destroy) ``` -------------------------------- ### 500 Error Page Styling (CSS) Source: https://github.com/basecamp/once-campfire/blob/main/public/500.html This CSS styles a 500 Internal Server Error page, including layout, colors (with dark mode support), error message presentation, and button styling. It uses CSS variables for theming and ensures responsiveness. ```css *, *::before, *::after { box-sizing: border-box; } body { --lch-black: 0% 0 0; --lch-gray: 75% 0.005 96; --lch-white: 100% 0 0; --color-border: oklch(var(--lch-gray)); --color-bg: oklch(var(--lch-white)); --color-text: oklch(var(--lch-black)); --btn-size: 2.65em; background-color: var(--color-bg); block-size: 100dvh; color: var(--color-text); display: grid; margin: 0; padding: 0; place-items: center; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; @media (prefers-color-scheme: dark) { --lch-black: 100% 0 0; --lch-gray: 44.95% 0 0; --lch-white: 0% 0 0; } } svg { fill: var(--color-text); @media (prefers-color-scheme: dark) { fill: var(--color-text); } } .error { align-items: center; display: flex; flex-direction: column; gap: 2em; justify-content: start; margin-block-end: 15dvh; } .error__img { aspect-ratio: 1; background-color: var(--color-text); block-size: auto; border-radius: 50%; display: grid; place-items: center; inline-size: 30dvh; svg { fill: var(--color-bg); grid-area: 1/1; max-inline-size: 66%; @media (prefers-color-scheme: dark) { fill: var(--color-bg); } } } .buttons { display: flex; flex-direction: row; gap: 1em; justify-content: center; } .btn { align-items: center; aspect-ratio: 1; background-color: var(--color-bg); block-size: var(--btn-size); border-radius: 50%; border: 1px solid var(--color-border); color: var(--color-text); cursor: pointer; display: grid; font-weight: 600; font-size: 1.4rem; gap: 0.5em; inline-size: var(--btn-size); justify-content: center; padding: 0; place-items: center; text-align: center; svg { -webkit-touch-callout: none; grid-area: 1/1; inline-size: 1.3em; max-inline-size: unset; user-select: none; } } .for-screen-reader { clip-path: inset(50%); height: 1px; width: 1px; overflow: hidden; position: absolute; white-space: nowrap; } ``` -------------------------------- ### Bot Authentication Source: https://context7.com/basecamp/once-campfire/llms.txt Authenticates a bot user using a provided bot key, typically passed as a URL parameter. If successful, sets the current user to the authenticated bot. ```ruby # Bot authentication (via URL parameter) if params[:bot_key].present? bot = User.authenticate_bot(params[:bot_key].strip) Current.user = bot if bot end ``` -------------------------------- ### Query Room Types Source: https://context7.com/basecamp/once-campfire/llms.txt Provides methods to query different types of rooms. These methods return collections of rooms based on their status (open, closed) or type (direct message, non-DM). ```ruby Room.opens # All open rooms Room.closeds # All closed rooms Room.directs # All direct message rooms Room.without_directs # All non-DM rooms Room.ordered # Alphabetically ordered by name ``` -------------------------------- ### User Display Properties Source: https://context7.com/basecamp/once-campfire/llms.txt Retrieves properties of a user suitable for display. Includes their initials derived from their name and a formatted title combining name and bio. ```ruby # User display properties user.initials # => "AS" (from "Alice Smith") user.title # => "Alice Smith – Product Designer" ``` -------------------------------- ### Web Push Notifications API Source: https://context7.com/basecamp/once-campfire/llms.txt Manages push subscriptions for enabling browser push notifications for new messages and mentions. ```APIDOC ## POST /users/me/push_subscriptions ### Description Registers or updates a user's push notification subscription for a specific browser or device. ### Method POST ### Endpoint /users/me/push_subscriptions ### Request Body - **push_subscription** (object) - Required - Contains details of the push subscription. - **endpoint** (string) - Required - The endpoint URL for receiving push notifications. - **p256dh_key** (string) - Required - The public key for encryption. - **auth_key** (string) - Required - The authentication secret. ### Request Example ```javascript const response = await fetch('/users/me/push_subscriptions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({ push_subscription: { endpoint: subscription.endpoint, p256dh_key: base64Encode(subscription.getKey('p256dh')), auth_key: base64Encode(subscription.getKey('auth')) } }) }); ``` ### Response #### Success Response (200) Indicates the push subscription was successfully registered or updated. ## DELETE /users/me/push_subscriptions/:id ### Description Unregisters a specific push notification subscription, effectively removing a device or browser from receiving push notifications. ### Method DELETE ### Endpoint /users/me/push_subscriptions/:id ### Parameters #### Path Parameters - **id** (integer) - Required - The unique identifier of the push subscription to remove. ### Response #### Success Response (200) Indicates the push subscription was successfully removed. ## DELETE /users/me/push_subscriptions ### Description Removes a push subscription associated with a specific endpoint, typically used during logout or when a user revokes notification permissions. ### Method DELETE ### Endpoint /users/me/push_subscriptions ### Request Body - **push_subscription_endpoint** (string) - Required - The endpoint URL of the push subscription to remove. ### Response #### Success Response (200) Indicates the push subscription was successfully removed. ``` -------------------------------- ### Create Text Message Source: https://context7.com/basecamp/once-campfire/llms.txt Creates a new text-based message within a room. Requires the message body, creator, and a unique client message ID for idempotency. ```ruby message = room.messages.create!( body: "Hello, team! Let\'s discuss the new feature.", creator: current_user, client_message_id: SecureRandom.uuid ) ``` -------------------------------- ### Room Management API Source: https://context7.com/basecamp/once-campfire/llms.txt This section covers the creation and management of different room types within Campfire, including open, closed, and direct message rooms. ```APIDOC ## Room Management ### Creating Rooms Campfire supports three room types: open (public), closed (private with member list), and direct (one-on-one or group DMs). #### Creating an Open Room Accessible to all users. ```ruby # Create an open room (accessible to all users) open_room = Rooms::Open.create_for( { name: "General Discussion" }, users: current_user ) ``` #### Creating a Closed Room Private rooms with a specific list of members. ```ruby # Create a closed room with specific members team_members = User.where(id: [1, 2, 3, 5]) closed_room = Rooms::Closed.create_for( { name: "Engineering Team" }, users: team_members ) ``` #### Creating or Finding a Direct Message Room For one-on-one or group direct messages. ```ruby # Create or find direct message room users = User.where(id: [current_user.id, other_user.id]) dm_room = Rooms::Direct.find_or_create_for(users) ``` #### Granting Access to Closed Rooms Add users to an existing closed room. ```ruby # Grant access to additional users (closed rooms only) closed_room.memberships.grant_to([user1, user2, user3]) ``` #### Revoking Access from Closed Rooms Remove users from an existing closed room. ```ruby # Revoke access from users closed_room.memberships.revoke_from([user4, user5]) ``` ``` -------------------------------- ### Campfire Bot Message Posting (cURL) Source: https://context7.com/basecamp/once-campfire/llms.txt Shows how to use cURL to post text messages and file attachments to Campfire rooms using a bot's authentication key. Requires the room ID and bot key to construct the API endpoint. ```bash ```bash # Post a text message to a room curl -X POST https://chat.example.com/rooms/123/42-5M0aLYwQyBXO/messages \ -H "Content-Type: text/plain" \ -d "Deployment to production completed successfully! ✓" # Post a message with UTF-8 characters curl -X POST https://chat.example.com/rooms/123/42-5M0aLYwQyBXO/messages \ -H "Content-Type: text/plain" \ -d "Hello 👋 from the bot!" # Upload a file attachment curl -X POST https://chat.example.com/rooms/123/42-5M0aLYwQyBXO/messages \ -F "attachment=@/path/to/report.pdf" # Response: 201 Created # Location: https://chat.example.com/rooms/123/messages/456 ``` ``` -------------------------------- ### Fetch Paginated Messages Source: https://context7.com/basecamp/once-campfire/llms.txt Retrieves messages in a paginated format. Supports fetching the last page, the page before a specific message, and the page after a specific message. ```ruby # Fetch paginated messages last_page = room.messages.with_creator.last_page page_before_msg = room.messages.page_before(specific_message) page_after_msg = room.messages.page_after(specific_message) ``` -------------------------------- ### Membership and Involvement API Source: https://context7.com/basecamp/once-campfire/llms.txt Manages user involvement levels in rooms, notification preferences, and room read status. ```APIDOC ## GET /memberships ### Description Retrieves a list of memberships for the current user, with options to filter by visibility and read status. ### Method GET ### Endpoint /memberships ### Query Parameters - **visible** (boolean) - Optional - If true, only includes memberships that are not invisible. - **unread** (boolean) - Optional - If true, only includes memberships with unread messages. - **without_direct_rooms** (boolean) - Optional - If true, excludes direct message rooms from the results. - **ordered_by_room_name** (boolean) - Optional - If true, orders the results by room name. ### Response #### Success Response (200) An array of membership objects. - **room** (object) - Details of the room. - **involvement** (string) - The user's involvement level ('invisible', 'nothing', 'mentions', 'everything'). - **unread_at** (datetime) - Timestamp when the room was last marked as unread. ## PUT /memberships/:room_id ### Description Updates the user's involvement level in a specific room and marks the room as read or unread. ### Method PUT ### Endpoint /memberships/:room_id ### Parameters #### Path Parameters - **room_id** (integer) - Required - The ID of the room to update. ### Request Body - **involvement** (string) - Optional - The new involvement level ('invisible', 'nothing', 'mentions', 'everything'). - **read** (boolean) - Optional - If true, marks the room as read. If false, marks as unread. ### Response #### Success Response (200) Indicates the membership was successfully updated. ## POST /users/reset_connections ### Description Resets all WebSocket connections for the current user, effectively disconnecting them from all rooms. ### Method POST ### Endpoint /users/reset_connections ### Response #### Success Response (200) Indicates that the user's connections have been reset. ``` -------------------------------- ### Subscribe to Room Messages (JavaScript) Source: https://context7.com/basecamp/once-campfire/llms.txt Subscribes to real-time updates for messages within a specific room using Action Cable. Handles connection events and incoming message data. ```javascript // Subscribe to room messages const roomChannel = consumer.subscriptions.create( { channel: "RoomChannel", room_id: 123 }, { connected() { console.log("Connected to room 123"); }, disconnected() { console.log("Disconnected from room 123"); }, received(data) { // Handle incoming message broadcast console.log("New message:", data); appendMessage(data); } } ); ``` -------------------------------- ### Ban User Source: https://context7.com/basecamp/once-campfire/llms.txt Bans a user, preventing them from participating. Requires a reason for the ban and the administrator who enacted the ban. ```ruby # Ban a user ban = user.bans.create!( reason: "Violation of terms of service", banned_by: admin_user ) ``` -------------------------------- ### Batch Update Memberships Source: https://context7.com/basecamp/once-campfire/llms.txt Allows for batch updating of room memberships by granting and revoking user access simultaneously. This operation modifies the membership status for specified users within a room. ```ruby closed_room.memberships.revise( granted: [user6, user7], revoked: [user8] ) ``` -------------------------------- ### Button Container and Button Styles Source: https://github.com/basecamp/once-campfire/blob/main/public/422.html Styles a container for buttons using flexbox for horizontal arrangement and spacing. Individual button styles include a circular shape, border, text color, and centered content, with specific sizes defined by CSS variables. ```css .buttons { display: flex; flex-direction: row; gap: 1em; justify-content: center; } .btn { align-items: center; aspect-ratio: 1; background-color: var(--color-bg); block-size: var(--btn-size); border-radius: 50%; border: 1px solid var(--color-border); color: var(--color-text); cursor: pointer; display: grid; font-weight: 600; font-size: 1.4rem; gap: 0.5em; inline-size: var(--btn-size); justify-content: center; padding: 0; place-items: center; text-align: center; } .btn svg { -webkit-touch-callout: none; grid-area: 1/1; inline-size: 1.3em; max-inline-size: unset; user-select: none; } ``` -------------------------------- ### Screen Reader Only Styles Source: https://github.com/basecamp/once-campfire/blob/main/public/422.html Defines styles for elements intended only for screen readers. This involves clipping the element's content and hiding it visually while keeping it accessible to assistive technologies. ```css .for-screen-reader { clip-path: inset(50%); height: 1px; width: 1px; overflow: hidden; position: absolute; white-space: nowrap; } ``` -------------------------------- ### Search Messages API Source: https://context7.com/basecamp/once-campfire/llms.txt Allows full-text search across all messages in rooms the user has access to. It also supports saving searches to history and clearing the search history. ```APIDOC ## GET /searches ### Description Performs a full-text search across messages accessible by the current user. ### Method GET ### Endpoint /searches ### Query Parameters - **q** (string) - Required - The search query string. Special characters will be removed. ### Request Example ```bash curl -X GET "https://chat.example.com/searches?q=deployment+status" \ -H "Cookie: session_token=abc123..." ``` ### Response #### Success Response (200) Returns an HTML page with matching messages. ## POST /searches ### Description Saves a search query to the user's recent searches history. ### Method POST ### Endpoint /searches ### Request Body - **q** (string) - Required - The search query to save. ### Request Example ```bash curl -X POST "https://chat.example.com/searches" \ -H "Cookie: session_token=abc123..." \ -d "q=important+keyword" ``` ## DELETE /searches/clear ### Description Clears all saved search history for the current user. ### Method DELETE ### Endpoint /searches/clear ### Request Example ```bash curl -X DELETE "https://chat.example.com/searches/clear" \ -H "Cookie: session_token=abc123..." ``` ``` -------------------------------- ### User Logout Source: https://context7.com/basecamp/once-campfire/llms.txt Logs out the current user by deleting the session token cookie and destroying the associated session. ```ruby # Logout cookies.delete(:session_token) session.destroy ``` -------------------------------- ### Page Auto-Reload JavaScript Source: https://github.com/basecamp/once-campfire/blob/main/public/502.html A simple JavaScript snippet that uses setTimeout to reload the current page after a specified delay. This is useful for applications that need to refresh their content periodically. ```javascript setTimeout(() => location.reload(), 10000) ``` -------------------------------- ### Error Section Styling Source: https://github.com/basecamp/once-campfire/blob/main/public/422.html Styles the error section with flexbox for layout, allowing vertical alignment of content. It includes a specific margin for the bottom and defines styles for an error image container. ```css .error { align-items: center; display: flex; flex-direction: column; gap: 2em; justify-content: start; margin-block-end: 15dvh; } .error__img { aspect-ratio: 1; background-color: var(--color-text); block-size: auto; border-radius: 50%; display: grid; place-items: center; inline-size: 30dvh; } .error__img svg { fill: var(--color-bg); grid-area: 1/1; max-inline-size: 66%; } @media (prefers-color-scheme: dark) { .error__img svg { fill: var(--color-bg); } } ``` -------------------------------- ### Campfire Webhook Notification Payload Structure (JSON) Source: https://context7.com/basecamp/once-campfire/llms.txt Illustrates the JSON structure of a webhook payload sent by Campfire when a bot is mentioned or receives a direct message. This payload contains details about the user, room, and message content. ```json ```json // Webhook payload structure { "user": { "id": 7, "name": "Alice Smith" }, "room": { "id": 123, "name": "General", "path": "/rooms/123/42-5M0aLYwQyBXO/messages" }, "message": { "id": 456, "body": { "html": "
@DeploymentBot check status
", "plain": "check status" }, "path": "/rooms/123/@456" } } ``` ``` -------------------------------- ### Check User Status Source: https://context7.com/basecamp/once-campfire/llms.txt Provides methods to check the current status of a user, such as whether they are active, deactivated, or banned. Returns a boolean value for each status. ```ruby # User status enum user.active? # => true user.deactivated? # => false user.banned? # => false ``` -------------------------------- ### Campfire Animation CSS Source: https://github.com/basecamp/once-campfire/blob/main/public/502.html Defines styles for a campfire animation, including background, SVG elements, and keyframe animations for color cycling, glow, and spark effects. It uses CSS variables for easy customization of colors and animation parameters. ```css body { --color-yellow: #ff0; --color-cyan: #00ffdd; --color-white: #fff; --color-black: #000; --color-bg: #0064e6; --opacity: 0.25; --animation-loop: 3s; --animation-duration: 200ms; background-color: var(--color-bg); block-size: 100dvh; display: grid; margin: 0; padding: 0; place-items: center; } svg { max-width: 50dvh; height: auto; aspect-ratio: 1; margin-block-end: 10dvh; } #glow, #spark, #shadow, #line-art, #lighter_tint { stroke-width: 0; } .line-art { fill: var(--color-black) } #lighter_tint { fill: var(--color-white); } #glow { fill: var(--color-white); animation: spark-glow var(--animation-loop) step-start infinite, cycle-colors var(--animation-duration) step-start infinite; } #spark, #lighter_glow { animation: spark var(--animation-loop) step-start infinite, cycle-colors var(--animation-duration) step-start infinite; } #shadow { opacity: var(--opacity); animation: spark-glow var(--animation-loop) step-start infinite, cycle-colors var(--animation-duration) step-start infinite; } @keyframes cycle-colors { 0% { fill: var(--color-yellow); } 33% { fill: var(--color-cyan); } 66% { fill: transparent; } 100% { fill: var(--color-yellow); } } @keyframes spark-glow { 0% { opacity: var(--opacity); } 10% { opacity: var(--opacity); } 100% { opacity: 0; } } @keyframes spark { 0% { opacity: 1; } 10% { opacity: 1; } 100% { opacity: 0; } } ``` -------------------------------- ### SVG Color Styling Source: https://github.com/basecamp/once-campfire/blob/main/public/422.html Sets the fill color for SVG elements, ensuring they match the text color. Includes a media query to maintain the text color as the fill color even in dark mode, providing visual consistency. ```css svg { fill: var(--color-text); } @media (prefers-color-scheme: dark) { svg { fill: var(--color-text); } } ``` -------------------------------- ### Check Message Content Type Source: https://context7.com/basecamp/once-campfire/llms.txt Determines the type of content a message holds, such as text, attachment, or sound command. Returns a boolean for each type. ```ruby # Message content types message.content_type.text? # => true message.content_type.attachment? # => true message.content_type.sound? # => true ``` -------------------------------- ### Check Room Type Source: https://context7.com/basecamp/once-campfire/llms.txt Returns a boolean indicating the current state or type of a room. These methods help determine if a room is open, closed, or a direct message. ```ruby room.open? # => true/false room.closed? # => true/false room.direct? # => true/false ``` -------------------------------- ### Deactivate User Source: https://context7.com/basecamp/once-campfire/llms.txt Deactivates a user account, performing a soft delete. This includes closing WebSocket connections, removing memberships (except DMs), deleting subscriptions, and anonymizing the email. ```ruby # Deactivate a user (soft delete with data cleanup) user.deactivate # - Closes remote WebSocket connections # - Removes memberships (except DM rooms) # - Deletes push subscriptions and sessions # - Anonymizes email address ``` -------------------------------- ### Update a Message Source: https://context7.com/basecamp/once-campfire/llms.txt Updates the content of an existing message. This operation can only be performed by the message creator or an administrator. ```ruby # Update a message (only by creator or admin) message.update!(body: "Updated message content") ``` -------------------------------- ### Delete a Message Source: https://context7.com/basecamp/once-campfire/llms.txt Permanently removes a message from the room. This action is irreversible. ```ruby # Delete a message message.destroy ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.