refac
This commit is contained in:
@@ -24,7 +24,7 @@ def upgrade() -> None:
|
|||||||
sa.Column('user_id', sa.Text(), nullable=False),
|
sa.Column('user_id', sa.Text(), nullable=False),
|
||||||
sa.Column('name', sa.Text(), nullable=False),
|
sa.Column('name', sa.Text(), nullable=False),
|
||||||
sa.Column('color', sa.Text(), nullable=True),
|
sa.Column('color', sa.Text(), nullable=True),
|
||||||
sa.Column('is_system', sa.Boolean(), nullable=False),
|
sa.Column('is_default', sa.Boolean(), nullable=False),
|
||||||
sa.Column('data', sa.JSON(), nullable=True),
|
sa.Column('data', sa.JSON(), nullable=True),
|
||||||
sa.Column('meta', sa.JSON(), nullable=True),
|
sa.Column('meta', sa.JSON(), nullable=True),
|
||||||
sa.Column('created_at', sa.BigInteger(), nullable=False),
|
sa.Column('created_at', sa.BigInteger(), nullable=False),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from sqlalchemy import (
|
|||||||
exists,
|
exists,
|
||||||
func,
|
func,
|
||||||
delete,
|
delete,
|
||||||
|
update,
|
||||||
)
|
)
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ class Calendar(Base):
|
|||||||
user_id = Column(Text, nullable=False)
|
user_id = Column(Text, nullable=False)
|
||||||
name = Column(Text, nullable=False)
|
name = Column(Text, nullable=False)
|
||||||
color = Column(Text, nullable=True)
|
color = Column(Text, nullable=True)
|
||||||
is_system = Column(Boolean, nullable=False, default=False)
|
is_default = Column(Boolean, nullable=False, default=False)
|
||||||
data = Column(JSON, nullable=True)
|
data = Column(JSON, nullable=True)
|
||||||
meta = Column(JSON, nullable=True)
|
meta = Column(JSON, nullable=True)
|
||||||
|
|
||||||
@@ -107,7 +108,8 @@ class CalendarModel(BaseModel):
|
|||||||
user_id: str
|
user_id: str
|
||||||
name: str
|
name: str
|
||||||
color: Optional[str] = None
|
color: Optional[str] = None
|
||||||
is_system: bool = False
|
is_default: bool = False
|
||||||
|
|
||||||
data: Optional[dict] = None
|
data: Optional[dict] = None
|
||||||
meta: Optional[dict] = None
|
meta: Optional[dict] = None
|
||||||
|
|
||||||
@@ -269,7 +271,7 @@ class CalendarTable:
|
|||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
name='Personal',
|
name='Personal',
|
||||||
color='#3b82f6',
|
color='#3b82f6',
|
||||||
is_system=True,
|
is_default=True,
|
||||||
created_at=now,
|
created_at=now,
|
||||||
updated_at=now,
|
updated_at=now,
|
||||||
),
|
),
|
||||||
@@ -278,7 +280,6 @@ class CalendarTable:
|
|||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
name='Scheduled Tasks',
|
name='Scheduled Tasks',
|
||||||
color='#8b5cf6',
|
color='#8b5cf6',
|
||||||
is_system=True,
|
|
||||||
created_at=now + 1,
|
created_at=now + 1,
|
||||||
updated_at=now + 1,
|
updated_at=now + 1,
|
||||||
),
|
),
|
||||||
@@ -338,7 +339,6 @@ class CalendarTable:
|
|||||||
select(Calendar).filter(
|
select(Calendar).filter(
|
||||||
Calendar.user_id == user_id,
|
Calendar.user_id == user_id,
|
||||||
Calendar.name == 'Scheduled Tasks',
|
Calendar.name == 'Scheduled Tasks',
|
||||||
Calendar.is_system == True,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
cal = result.scalars().first()
|
cal = result.scalars().first()
|
||||||
@@ -349,7 +349,6 @@ class CalendarTable:
|
|||||||
select(Calendar).filter(
|
select(Calendar).filter(
|
||||||
Calendar.user_id == user_id,
|
Calendar.user_id == user_id,
|
||||||
Calendar.name == 'Scheduled Tasks',
|
Calendar.name == 'Scheduled Tasks',
|
||||||
Calendar.is_system == True,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
cal = result.scalars().first()
|
cal = result.scalars().first()
|
||||||
@@ -366,7 +365,7 @@ class CalendarTable:
|
|||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
name=form_data.name,
|
name=form_data.name,
|
||||||
color=form_data.color,
|
color=form_data.color,
|
||||||
is_system=False,
|
is_default=False,
|
||||||
data=form_data.data,
|
data=form_data.data,
|
||||||
meta=form_data.meta,
|
meta=form_data.meta,
|
||||||
created_at=now,
|
created_at=now,
|
||||||
@@ -403,13 +402,36 @@ class CalendarTable:
|
|||||||
await db.commit()
|
await db.commit()
|
||||||
return await self._to_calendar_model(cal, db=db)
|
return await self._to_calendar_model(cal, db=db)
|
||||||
|
|
||||||
|
async def set_default_calendar(
|
||||||
|
self, user_id: str, calendar_id: str, db: Optional[AsyncSession] = None
|
||||||
|
) -> Optional[CalendarModel]:
|
||||||
|
"""Set a calendar as the user's default, clearing all others."""
|
||||||
|
async with get_async_db_context(db) as db:
|
||||||
|
# Clear all defaults for this user
|
||||||
|
await db.execute(
|
||||||
|
update(Calendar)
|
||||||
|
.where(Calendar.user_id == user_id, Calendar.is_default == True)
|
||||||
|
.values(is_default=False)
|
||||||
|
)
|
||||||
|
# Set the new default
|
||||||
|
result = await db.execute(
|
||||||
|
select(Calendar).filter(Calendar.id == calendar_id, Calendar.user_id == user_id)
|
||||||
|
)
|
||||||
|
cal = result.scalars().first()
|
||||||
|
if not cal:
|
||||||
|
return None
|
||||||
|
cal.is_default = True
|
||||||
|
cal.updated_at = int(time.time_ns())
|
||||||
|
await db.commit()
|
||||||
|
return await self._to_calendar_model(cal, db=db)
|
||||||
|
|
||||||
async def delete_calendar_by_id(self, id: str, db: Optional[AsyncSession] = None) -> bool:
|
async def delete_calendar_by_id(self, id: str, db: Optional[AsyncSession] = None) -> bool:
|
||||||
"""Delete a non-system calendar. Cascades to events, attendees, and grants."""
|
"""Delete a non-default calendar. Cascades to events, attendees, and grants."""
|
||||||
try:
|
try:
|
||||||
async with get_async_db_context(db) as db:
|
async with get_async_db_context(db) as db:
|
||||||
result = await db.execute(select(Calendar).filter(Calendar.id == id))
|
result = await db.execute(select(Calendar).filter(Calendar.id == id))
|
||||||
cal = result.scalars().first()
|
cal = result.scalars().first()
|
||||||
if not cal or cal.is_system:
|
if not cal or cal.is_default:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Delete attendees for all events in this calendar
|
# Delete attendees for all events in this calendar
|
||||||
|
|||||||
@@ -310,10 +310,16 @@ async def delete_calendar(calendar_id: str, user: UserModel = Depends(get_verifi
|
|||||||
if cal.user_id != user.id and user.role != 'admin':
|
if cal.user_id != user.id and user.role != 'admin':
|
||||||
raise HTTPException(status_code=403, detail='Only owner can delete calendar')
|
raise HTTPException(status_code=403, detail='Only owner can delete calendar')
|
||||||
|
|
||||||
if cal.is_system:
|
|
||||||
raise HTTPException(status_code=400, detail='Cannot delete system calendar')
|
|
||||||
|
|
||||||
result = await Calendars.delete_calendar_by_id(calendar_id)
|
result = await Calendars.delete_calendar_by_id(calendar_id)
|
||||||
if not result:
|
if not result:
|
||||||
raise HTTPException(status_code=500, detail='Failed to delete')
|
raise HTTPException(status_code=500, detail='Failed to delete')
|
||||||
return {'status': True}
|
return {'status': True}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post('/{calendar_id}/default')
|
||||||
|
async def set_default_calendar(calendar_id: str, user: UserModel = Depends(get_verified_user)):
|
||||||
|
cal = await Calendars.set_default_calendar(user.id, calendar_id)
|
||||||
|
if not cal:
|
||||||
|
raise HTTPException(status_code=404, detail='Calendar not found')
|
||||||
|
return cal
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export type CalendarModel = {
|
|||||||
user_id: string;
|
user_id: string;
|
||||||
name: string;
|
name: string;
|
||||||
color: string | null;
|
color: string | null;
|
||||||
is_system: boolean;
|
is_default: boolean;
|
||||||
data: Record<string, any> | null;
|
data: Record<string, any> | null;
|
||||||
meta: Record<string, any> | null;
|
meta: Record<string, any> | null;
|
||||||
access_grants: any[];
|
access_grants: any[];
|
||||||
@@ -188,6 +188,37 @@ export const deleteCalendar = async (token: string, calendarId: string): Promise
|
|||||||
return res?.status ?? false;
|
return res?.status ?? false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setDefaultCalendar = async (
|
||||||
|
token: string,
|
||||||
|
calendarId: string
|
||||||
|
): Promise<CalendarModel> => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/${calendarId}/default`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
authorization: `Bearer ${token}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) throw await res.json();
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
error = err.detail;
|
||||||
|
console.error(err);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
// ── Events ─────────────────────────────────
|
// ── Events ─────────────────────────────────
|
||||||
|
|
||||||
export const getCalendarEvents = async (
|
export const getCalendarEvents = async (
|
||||||
|
|||||||
@@ -128,7 +128,7 @@
|
|||||||
showEventModal = true;
|
showEventModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$: defaultCalendarId = calendars.find((c) => !c.is_system || c.name === 'Personal')?.id || calendars[0]?.id || '';
|
$: defaultCalendarId = calendars.find((c) => c.is_default)?.id || calendars[0]?.id || '';
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await loadCalendars();
|
await loadCalendars();
|
||||||
|
|||||||
Reference in New Issue
Block a user