feat: add access control to channels with various modes
- Introduced AccessMode enum to define channel access levels: Public, PasswordProtected, AccountRequired, and OwnerOnly. - Updated Channel and ProgrammingBlock entities to include access_mode and access_password_hash fields. - Enhanced create and update channel functionality to handle access mode and password. - Implemented access checks in channel routes based on the defined access modes. - Modified frontend components to support channel creation and editing with access control options. - Added ChannelPasswordModal for handling password input when accessing restricted channels. - Updated API calls to include channel and block passwords as needed. - Created database migrations to add access_mode and access_password_hash columns to channels table.
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
DialogFooter,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import type { AccessMode } from "@/lib/types";
|
||||
|
||||
interface CreateChannelDialogProps {
|
||||
open: boolean;
|
||||
@@ -17,6 +18,8 @@ interface CreateChannelDialogProps {
|
||||
name: string;
|
||||
timezone: string;
|
||||
description: string;
|
||||
access_mode?: AccessMode;
|
||||
access_password?: string;
|
||||
}) => void;
|
||||
isPending: boolean;
|
||||
error?: string | null;
|
||||
@@ -32,10 +35,18 @@ export function CreateChannelDialog({
|
||||
const [name, setName] = useState("");
|
||||
const [timezone, setTimezone] = useState("UTC");
|
||||
const [description, setDescription] = useState("");
|
||||
const [accessMode, setAccessMode] = useState<AccessMode>("public");
|
||||
const [accessPassword, setAccessPassword] = useState("");
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
onSubmit({ name, timezone, description });
|
||||
onSubmit({
|
||||
name,
|
||||
timezone,
|
||||
description,
|
||||
access_mode: accessMode !== "public" ? accessMode : undefined,
|
||||
access_password: accessMode === "password_protected" && accessPassword ? accessPassword : undefined,
|
||||
});
|
||||
};
|
||||
|
||||
const handleOpenChange = (next: boolean) => {
|
||||
@@ -45,6 +56,8 @@ export function CreateChannelDialog({
|
||||
setName("");
|
||||
setTimezone("UTC");
|
||||
setDescription("");
|
||||
setAccessMode("public");
|
||||
setAccessPassword("");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -99,6 +112,33 @@ export function CreateChannelDialog({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="block text-xs font-medium text-zinc-400">Access</label>
|
||||
<select
|
||||
value={accessMode}
|
||||
onChange={(e) => setAccessMode(e.target.value as AccessMode)}
|
||||
className="w-full rounded-md border border-zinc-700 bg-zinc-800 px-3 py-2 text-sm text-zinc-100 focus:border-zinc-500 focus:outline-none"
|
||||
>
|
||||
<option value="public">Public</option>
|
||||
<option value="password_protected">Password protected</option>
|
||||
<option value="account_required">Account required</option>
|
||||
<option value="owner_only">Owner only</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{accessMode === "password_protected" && (
|
||||
<div className="space-y-1.5">
|
||||
<label className="block text-xs font-medium text-zinc-400">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
value={accessPassword}
|
||||
onChange={(e) => setAccessPassword(e.target.value)}
|
||||
placeholder="Channel password"
|
||||
className="w-full rounded-md border border-zinc-700 bg-zinc-800 px-3 py-2 text-sm text-zinc-100 placeholder:text-zinc-600 focus:border-zinc-500 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && <p className="text-xs text-red-400">{error}</p>}
|
||||
|
||||
<DialogFooter>
|
||||
|
||||
Reference in New Issue
Block a user