#[non_exhaustive]pub struct User {
pub id: i64,
pub name: String,
pub email: String,
pub password: String,
pub email_verified_at: Option<DateTime>,
pub created_at: Option<DateTime>,
pub updated_at: Option<DateTime>,
pub extra: BTreeMap<String, Value>,
}Expand description
A row of the users table created by the Auth module.
Columns the app adds with its own migration (a role, a phone) are
kept in extra: read them with user.get::<String>("role"), change them
with user.set(&db, "role", "admin"), filter with
User::where_eq("role", "admin"). Templates and JSON see them as the
user’s own fields ({{ auth.user.role }}). A typed model on the same
table (#[model(table = "users")] struct Member) works too.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.id: i64The users row id; 0 before it is saved.
name: StringThe display name.
email: StringThe email address (Renox’s forms store it trimmed and lowercased).
password: StringThe Argon2 hash; never serialized, so it can’t leak into templates or JSON.
email_verified_at: Option<DateTime>When the email address was confirmed; None while unverified.
created_at: Option<DateTime>When the account was created.
updated_at: Option<DateTime>When the row was last saved.
extra: BTreeMap<String, Value>The app’s own columns, by name.
Implementations§
Source§impl User
impl User
Sourcepub async fn delete_account(&self, db: &Db) -> Result
pub async fn delete_account(&self, db: &Db) -> Result
Deletes the user (their tokens, notifications and sessions go with the row) and their data grid preferences. The account page’s “delete account” does this.
Source§impl User
impl User
Sourcepub async fn notifications(
&self,
db: &Db,
limit: u32,
) -> Result<Vec<DatabaseNotification>>
pub async fn notifications( &self, db: &Db, limit: u32, ) -> Result<Vec<DatabaseNotification>>
The user’s notifications, newest first.
Sourcepub async fn notifications_before(
&self,
db: &Db,
before: i64,
limit: u32,
) -> Result<Vec<DatabaseNotification>>
pub async fn notifications_before( &self, db: &Db, before: i64, limit: u32, ) -> Result<Vec<DatabaseNotification>>
The user’s notifications older than the one with id before,
newest first: the next page after a list ending at before.
Sourcepub async fn notification(
&self,
db: &Db,
id: i64,
) -> Result<Option<DatabaseNotification>>
pub async fn notification( &self, db: &Db, id: i64, ) -> Result<Option<DatabaseNotification>>
One of the user’s notifications, or None if it isn’t theirs.
Sourcepub async fn unread_notifications(
&self,
db: &Db,
) -> Result<Vec<DatabaseNotification>>
pub async fn unread_notifications( &self, db: &Db, ) -> Result<Vec<DatabaseNotification>>
The user’s unread notifications, newest first.
Sourcepub async fn unread_notification_count(&self, db: &Db) -> Result<i64>
pub async fn unread_notification_count(&self, db: &Db) -> Result<i64>
How many of the user’s notifications are unread.
Sourcepub async fn mark_notification_read(&self, db: &Db, id: i64) -> Result<bool>
pub async fn mark_notification_read(&self, db: &Db, id: i64) -> Result<bool>
Marks one of the user’s notifications read; returns whether it was theirs.
Sourcepub async fn mark_notification_unread(&self, db: &Db, id: i64) -> Result<bool>
pub async fn mark_notification_unread(&self, db: &Db, id: i64) -> Result<bool>
Marks one of the user’s notifications unread again; returns whether it was theirs.
Sourcepub async fn delete_notification(&self, db: &Db, id: i64) -> Result<bool>
pub async fn delete_notification(&self, db: &Db, id: i64) -> Result<bool>
Deletes one of the user’s notifications; returns whether it was theirs.
Sourcepub async fn delete_notifications(&self, db: &Db) -> Result<u64>
pub async fn delete_notifications(&self, db: &Db) -> Result<u64>
Deletes all the user’s notifications; returns how many there were.
Sourcepub async fn mark_all_notifications_read(&self, db: &Db) -> Result<u64>
pub async fn mark_all_notifications_read(&self, db: &Db) -> Result<u64>
Marks all the user’s unread notifications read; returns how many there were.
Source§impl User
impl User
Sourcepub async fn assign_role(&self, db: &Db, role: &str) -> Result
pub async fn assign_role(&self, db: &Db, role: &str) -> Result
Gives the user the existing role role (see
permissions::define_role) everywhere and for good.
Sourcepub fn assign_role_in<'a>(
&self,
db: &'a Db,
role: &'a str,
scope: &Scope,
) -> AssignRole<'a>
pub fn assign_role_in<'a>( &self, db: &'a Db, role: &'a str, scope: &Scope, ) -> AssignRole<'a>
Gives the user the existing role role in scope (a store, a
team), optionally from / until a date; .await it:
user.assign_role_in(&db, "manager", &Scope::of(&store)).until(end).await?.
It counts when that scope is the request’s (set_scope) and for
User::has_permission_in on that scope. With
Scope::global, it is a global role with dates.
Sourcepub async fn remove_role(&self, db: &Db, role: &str) -> Result
pub async fn remove_role(&self, db: &Db, role: &str) -> Result
Takes the global role role away from the user (roles given in a
scope stay; see User::remove_role_in).
Sourcepub async fn remove_role_in(&self, db: &Db, role: &str, scope: &Scope) -> Result
pub async fn remove_role_in(&self, db: &Db, role: &str, scope: &Scope) -> Result
Takes the role role in scope away from the user.
Sourcepub async fn sync_roles(&self, db: &Db, roles: &[&str]) -> Result
pub async fn sync_roles(&self, db: &Db, roles: &[&str]) -> Result
Makes the user’s global roles exactly roles (each must exist);
roles given in a scope stay.
Sourcepub async fn sync_roles_in(
&self,
db: &Db,
roles: &[&str],
scope: &Scope,
) -> Result
pub async fn sync_roles_in( &self, db: &Db, roles: &[&str], scope: &Scope, ) -> Result
Makes the user’s roles in scope exactly roles (each must exist),
with no dates; other scopes stay.
Sourcepub async fn roles(&self, db: &Db) -> Result<Vec<String>>
pub async fn roles(&self, db: &Db) -> Result<Vec<String>>
The names of the user’s roles in effect now, sorted: the global ones
plus those in the request’s scope (set_scope), within their
dates.
Sourcepub async fn permissions(&self, db: &Db) -> Result<Vec<String>>
pub async fn permissions(&self, db: &Db) -> Result<Vec<String>>
The permissions the user’s roles in effect now grant, sorted (the
same roles as User::roles).
Sourcepub async fn assignments(&self, db: &Db) -> Result<Vec<Assignment>>
pub async fn assignments(&self, db: &Db) -> Result<Vec<Assignment>>
Every role the user was given, with where and when, ordered by role
and scope; ended ones too until permissions:prune deletes them.
For account and admin pages.
Sourcepub fn has_role_in(&self, role: &str, scope: &Scope) -> bool
pub fn has_role_in(&self, role: &str, scope: &Scope) -> bool
Whether this user has role globally or in scope, within its
dates, from the roles loaded for the current request (like
User::has_role); scope is the record’s, not the request’s.
Sourcepub fn has_permission_in(&self, permission: &str, scope: &Scope) -> bool
pub fn has_permission_in(&self, permission: &str, scope: &Scope) -> bool
Whether a global role of this user, or one given in scope, grants
permission now: for policies, which check the record’s scope
(Scope::of_id::<Store>(order.store_id)) rather than the request’s.
Answered from the roles loaded for the current request (like
User::has_permission): false for another user and outside a
request.
Sourcepub fn scopes_with<M: Model>(&self, permission: &str) -> Scopes<M::Key>
pub fn scopes_with<M: Model>(&self, permission: &str) -> Scopes<M::Key>
The records of model M in which this user holds permission now:
Scopes::All when a global role grants it, else the keys of the
records whose roles do. For filtering lists (Scopes::apply).
Answered from the roles loaded for the current request; nothing for
another user and outside a request.
Source§impl User
impl User
Sourcepub async fn create_token(
&self,
db: &Db,
name: &str,
expires_at: Option<DateTime>,
) -> Result<NewToken>
pub async fn create_token( &self, db: &Db, name: &str, expires_at: Option<DateTime>, ) -> Result<NewToken>
Creates an API token that may do everything the user may, optionally
expiring at expires_at.
Sourcepub async fn create_token_with(
&self,
db: &Db,
name: &str,
abilities: &[&str],
expires_at: Option<DateTime>,
) -> Result<NewToken>
pub async fn create_token_with( &self, db: &Db, name: &str, abilities: &[&str], expires_at: Option<DateTime>, ) -> Result<NewToken>
Creates an API token limited to abilities (checked with
AuthUser::token_can or Routes::require_ability), e.g. a read-only
token: create_token_with(&db, "reports", &["orders:read"], None).
"*" allows everything.
Sourcepub async fn tokens(&self, db: &Db) -> Result<Vec<AccessToken>>
pub async fn tokens(&self, db: &Db) -> Result<Vec<AccessToken>>
The user’s API tokens, newest first.
Sourcepub async fn revoke_token(&self, db: &Db, token_id: i64) -> Result<bool>
pub async fn revoke_token(&self, db: &Db, token_id: i64) -> Result<bool>
Revokes one of the user’s tokens; returns whether it existed.
Sourcepub async fn revoke_tokens(&self, db: &Db) -> Result<u64>
pub async fn revoke_tokens(&self, db: &Db) -> Result<u64>
Revokes all of the user’s tokens.
Source§impl User
impl User
Sourcepub fn find_by_email<'c, E: Executor<'c>>(
db: E,
email: &str,
) -> impl Future<Output = Result<Option<Self>>> + Send
pub fn find_by_email<'c, E: Executor<'c>>( db: E, email: &str, ) -> impl Future<Output = Result<Option<Self>>> + Send
Emails are matched case-insensitively.
Sourcepub async fn register(
db: &Db,
name: &str,
email: &str,
password: &str,
) -> Result<Self>
pub async fn register( db: &Db, name: &str, email: &str, password: &str, ) -> Result<Self>
Creates a user with a hashed password.
Sourcepub async fn set_password(&mut self, db: &Db, password: &str) -> Result
pub async fn set_password(&mut self, db: &Db, password: &str) -> Result
Changes the password. Every session of the user ends, this one too
(sessions hold a fingerprint of the password hash); in a handler use
crate::auth::change_password, which logs this session in again.
Sourcepub fn get<T: DeserializeOwned>(&self, column: &str) -> Option<T>
pub fn get<T: DeserializeOwned>(&self, column: &str) -> Option<T>
One of the app’s own columns (see extra), e.g.
user.get::<String>("role"); None if missing, null or of another type.
A BOOLEAN column reads as bool on SQLite too, where it is stored as
0 or 1.
Sourcepub async fn set(
&mut self,
db: &Db,
column: &str,
value: impl ToDbValue,
) -> Result
pub async fn set( &mut self, db: &Db, column: &str, value: impl ToDbValue, ) -> Result
Sets one of the app’s own columns in the database and in extra, e.g.
user.set(&db, "role", "admin").
Sourcepub async fn revoke_sessions(&self, db: &Db) -> Result
pub async fn revoke_sessions(&self, db: &Db) -> Result
Ends every session of the user, e.g. on logout or when an account
may be compromised. API tokens stay; see User::revoke_tokens.
Sourcepub async fn attempt(
db: &Db,
email: &str,
password: &str,
) -> Result<Option<Self>>
pub async fn attempt( db: &Db, email: &str, password: &str, ) -> Result<Option<Self>>
The user with this email and password, e.g. to issue an API token. Takes as long for an unknown email as for a wrong password, so the answer doesn’t reveal which emails have accounts.
Sourcepub fn has_password(&self) -> bool
pub fn has_password(&self) -> bool
Whether the user has a password. Users made by a social login
(auth::register_verified, the renox-oauth crate) don’t: their
password is empty, which no typed password matches, until they
choose one with “Forgot your password?”.
Sourcepub async fn check_password(&self, password: &str) -> bool
pub async fn check_password(&self, password: &str) -> bool
Whether password matches the stored hash (Argon2id or an imported bcrypt one).
Sourcepub fn can(&self, ability: &str, target: &impl Policy) -> bool
pub fn can(&self, ability: &str, target: &impl Policy) -> bool
Whether target’s Policy allows this user ability.
Like User::can, but a refusal becomes a 403 error.
Source§impl User
impl User
Sourcepub fn has_role(&self, role: &str) -> bool
pub fn has_role(&self, role: &str) -> bool
Whether this user has role (the Permissions module), answered
from the roles loaded for the current request, so it works in
Policy::allows and App::gate_before (“admins may do anything”).
It is false for any other user, and outside a request (a job, a
command): use the async user.roles(&db) there.
Global roles count, plus those given in the request’s scope
(permissions::set_scope), within their dates.
Sourcepub fn has_permission(&self, permission: &str) -> bool
pub fn has_permission(&self, permission: &str) -> bool
Like User::has_role, for a permission granted by one of the
user’s roles.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for User
impl<'de> Deserialize<'de> for User
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl Model for User
impl Model for User
Source§const TABLE: &'static str = "users"
const TABLE: &'static str = "users"
#[model(table = …)]).Source§const SELECT_ALL: bool = true
const SELECT_ALL: bool = true
*) instead of COLUMNS, so from_row also
sees columns the struct doesn’t list, and queries may filter on them.
The built-in User does this to keep the app’s own columns.Source§const SOFT_DELETES: bool = false
const SOFT_DELETES: bool = false
delete() sets deleted_at instead of removing the row, and queries
skip deleted rows unless asked with with_trashed() / only_trashed().Source§const SEARCHABLE: &'static [&'static str] = _
const SEARCHABLE: &'static [&'static str] = _
#[model(search = "title, body")]; see
renox::db::search.Source§const SEARCH_LANGUAGE: &'static str = "english"
const SEARCH_LANGUAGE: &'static str = "english"
english (the
default) or a PostgreSQL text search configuration such as simple
(no stemming) or spanish. Set it with
#[model(search_language = "simple")].Source§fn replicate(&self) -> Selfwhere
Self: Clone,
fn replicate(&self) -> Selfwhere
Self: Clone,
replicate):
the same values, with an unsaved id, no deleted_at and, when they
are Options, no timestamps, so save inserts a new row. Change
what must differ (a unique SKU, a name) before saving it, or show it
in the “new” form for someone to finish (“Duplicate”). Read moreSource§fn default_scope(query: Query<Self>) -> Query<Self>
fn default_scope(query: Query<Self>) -> Query<Self>
renox::context. query(),
find, all, where_eq and the relation loaders apply it;
Model::unscoped doesn’t. Saving, deleting and restoring a loaded
model work by its id. Set it with #[model(default_scope = "…")]: Read moreSource§fn saving(&mut self, _creating: bool) -> Result
fn saving(&mut self, _creating: bool) -> Result
ModelHooks and add #[model(hooks)] rather than overriding it.Source§fn saved(&self, _created: bool) -> impl Future<Output = Result> + Send
fn saved(&self, _created: bool) -> impl Future<Output = Result> + Send
save. See ModelHooks.Source§fn query() -> Query<Self>
fn query() -> Query<Self>
Model::default_scope).Source§fn unscoped() -> Query<Self>
fn unscoped() -> Query<Self>
Source§fn refresh(&mut self, db: &Db) -> impl Future<Output = Result<()>> + Send
fn refresh(&mut self, db: &Db) -> impl Future<Output = Result<()>> + Send
increment or another request
changed it); a deleted row is a 404.Source§fn search(words: &str) -> Query<Self>
fn search(words: &str) -> Query<Self>
query().search(words). The model needs
#[model(search = "…")] and its index (see
renox::db::search). Read moreSource§fn where_eq(column: &str, value: impl ToDbValue) -> Query<Self>
fn where_eq(column: &str, value: impl ToDbValue) -> Query<Self>
query().where_eq(column, value).Source§fn all<'c, E: Executor<'c>>(
db: E,
) -> impl Future<Output = Result<Vec<Self>>> + Send
fn all<'c, E: Executor<'c>>( db: E, ) -> impl Future<Output = Result<Vec<Self>>> + Send
Source§fn find<'c, E: Executor<'c>>(
db: E,
id: Self::Key,
) -> impl Future<Output = Result<Option<Self>>> + Send
fn find<'c, E: Executor<'c>>( db: E, id: Self::Key, ) -> impl Future<Output = Result<Option<Self>>> + Send
None.Source§fn find_many<'c, E: Executor<'c>>(
db: E,
ids: impl IntoIterator<Item = Self::Key>,
) -> impl Future<Output = Result<Vec<Self>>> + Send
fn find_many<'c, E: Executor<'c>>( db: E, ids: impl IntoIterator<Item = Self::Key>, ) -> impl Future<Output = Result<Vec<Self>>> + Send
Source§fn insert_many<'c, E: Executor<'c>>(
db: E,
models: Vec<Self>,
) -> impl Future<Output = Result<u64>> + Send
fn insert_many<'c, E: Executor<'c>>( db: E, models: Vec<Self>, ) -> impl Future<Output = Result<u64>> + Send
create when you need them). Timestamps are set; unsaved ULID
and UUID keys are made, String keys must be set, i64 keys come
from the database. Returns the number of rows inserted.Source§fn upsert<'c, E: Executor<'c>>(
db: E,
models: Vec<Self>,
unique_by: &[&str],
update: &[&str],
) -> impl Future<Output = Result<u64>> + Send
fn upsert<'c, E: Executor<'c>>( db: E, models: Vec<Self>, unique_by: &[&str], update: &[&str], ) -> impl Future<Output = Result<u64>> + Send
models, or updates the rows they clash with on the
unique_by columns (which need a unique index), setting update
columns (and updated_at when the model has it). Returns the rows
written. Read moreSource§fn find_or_404<'c, E: Executor<'c>>(
db: E,
id: Self::Key,
) -> impl Future<Output = Result<Self>> + Send
fn find_or_404<'c, E: Executor<'c>>( db: E, id: Self::Key, ) -> impl Future<Output = Result<Self>> + Send
find, but a missing row becomes a 404 response.Source§fn create<'c, E: Executor<'c>>(
db: E,
model: Self,
) -> impl Future<Output = Result<Self>> + Send
fn create<'c, E: Executor<'c>>( db: E, model: Self, ) -> impl Future<Output = Result<Self>> + Send
Source§fn insert<'c, E: Executor<'c>>(
&mut self,
db: E,
) -> impl Future<Output = Result> + Send
fn insert<'c, E: Executor<'c>>( &mut self, db: E, ) -> impl Future<Output = Result> + Send
i64, a new ULID or UUID v7), a set
one is written as it is (a String key must be set).Source§fn save<'c, E: Executor<'c>>(
&mut self,
db: E,
) -> impl Future<Output = Result> + Send
fn save<'c, E: Executor<'c>>( &mut self, db: E, ) -> impl Future<Output = Result> + Send
0, an empty ULID…),
otherwise updates its row.Source§fn save_only<'c, E: Executor<'c>>(
&mut self,
db: E,
columns: &[&str],
) -> impl Future<Output = Result> + Send
fn save_only<'c, E: Executor<'c>>( &mut self, db: E, columns: &[&str], ) -> impl Future<Output = Result> + Send
columns (and updated_at, if the model has it) of a
saved model, so a concurrent change to another column isn’t
overwritten. A column the saving hook changes is saved only if
it’s listed. Read moreSource§fn save_changes<'c, E: Executor<'c>>(
&mut self,
db: E,
original: &Self,
) -> impl Future<Output = Result<bool>> + Send
fn save_changes<'c, E: Executor<'c>>( &mut self, db: E, original: &Self, ) -> impl Future<Output = Result<bool>> + Send
original (the model as it was
loaded), including those the saving hook changes, and returns
whether anything was written. When nothing changed there’s no query
and no saved hook. Read moreSource§fn delete<'c, E: Executor<'c>>(
&mut self,
db: E,
) -> impl Future<Output = Result> + Send
fn delete<'c, E: Executor<'c>>( &mut self, db: E, ) -> impl Future<Output = Result> + Send
Auto Trait Implementations§
impl Freeze for User
impl RefUnwindSafe for User
impl Send for User
impl Sync for User
impl Unpin for User
impl UnsafeUnpin for User
impl UnwindSafe for User
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more