Merge NEXT: planning, generation map and portable configuration on top of the OIDC access model
NEXT predates the access work, so the identity layer follows master: access comes from configured groups, instance administrators replace the site administration, and accounts are created by SSO or by an administrator. Kept from NEXT: manual publication with the Review changes panel and shared generator drafts, portable import/export (meguri/v2), the layered generation map with binding provenance, JSM provider changes, contact/approval semantics and the account-owned Person. Dropped: site administration, local sign-up, and the mandatory unique email with its contact/account migrations. The manual-publication migration is renumbered m_0010 after m_0009_access. Accounts without an email still get a Person in every workspace they reach, a changed sign-in email updates the account's person, and an account that loses access keeps its linked person so schedules stay valid. Instance administrators may use Sync and shared drafts. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
commit
38105c65c2
57 files changed
+6890
-431
No files matched your search
+22
-9
@@ -45,20 +45,25 @@ impl Permission {
|
||||
pub struct User {
|
||||
#[serde(default)]
|
||||
pub language: Option<String>,
|
||||
pub id: Uuid,
|
||||
/// Canonical account-owned person; email is required by account persistence.
|
||||
#[serde(flatten)]
|
||||
pub person: Person,
|
||||
pub username: String,
|
||||
pub display_name: String,
|
||||
pub country: String,
|
||||
/// None follows the browser timezone; this never changes scheduling rules.
|
||||
pub timezone: Option<String>,
|
||||
#[serde(default)]
|
||||
pub email: Option<String>,
|
||||
#[serde(default)]
|
||||
pub instance_admin: bool,
|
||||
#[serde(default)]
|
||||
pub has_password: bool,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for User {
|
||||
type Target = Person;
|
||||
fn deref(&self) -> &Person {
|
||||
&self.person
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Member {
|
||||
pub user: User,
|
||||
@@ -191,9 +196,7 @@ impl WorkspaceDocument {
|
||||
)?;
|
||||
validate_name(&person.display_name)?;
|
||||
ensure(
|
||||
person
|
||||
.user_id
|
||||
.is_none_or(|id| id == person.id && members.contains(&id)),
|
||||
person.user_id.is_none_or(|id| id == person.id),
|
||||
crate::i18n::text("err_choose_a_user_who_has_access_to_this_workspace_41cf15"),
|
||||
)?;
|
||||
ensure(
|
||||
@@ -450,7 +453,8 @@ impl WorkspaceDocument {
|
||||
} = &self.integration
|
||||
{
|
||||
ensure(
|
||||
Uuid::parse_str(cloud_id).is_ok() && Uuid::parse_str(team_id).is_ok(),
|
||||
Uuid::parse_str(cloud_id).is_ok()
|
||||
&& Uuid::parse_str(team_id.strip_prefix("og-").unwrap_or(team_id)).is_ok(),
|
||||
crate::i18n::text("err_jsm_cloud_and_team_ids_must_be_uuids_f75b5f"),
|
||||
)?;
|
||||
ensure(
|
||||
@@ -726,3 +730,12 @@ pub struct Timeline {
|
||||
pub to: DateTime<Utc>,
|
||||
pub assignments: Vec<Assignment>,
|
||||
}
|
||||
|
||||
/// A compact representation of a verified calendar-day cycle, independent of providers.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RecurringRotation {
|
||||
pub start: DateTime<Utc>,
|
||||
pub end: DateTime<Utc>,
|
||||
pub shift_days: u16,
|
||||
pub participants: Vec<Uuid>,
|
||||
}
|
||||
Reference in new issue
Block a user