Skip to content

Commit

Permalink
Add account_status field (active, unverified or deactivated) to Peo…
Browse files Browse the repository at this point in the history
…ple model (#687)

* Add account_status in People and a way to update it in admin-dashboard

- Add verified col and replace user ID with contact_email

* Replace account_status "TOMBSTONED" with "DISABLED"

* Add confirmation dialogue for account status

* Replace dropdown with button to edit account_status

* Replace account_status "disabled" with "deactivated"
  • Loading branch information
BenjaminCharmes authored Apr 19, 2024
1 parent bf4ba17 commit bc4a393
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 7 deletions.
11 changes: 11 additions & 0 deletions pydatalab/pydatalab/models/people.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ def __new__(cls, value):
return cls.validate(value)


class AccountStatus(str, Enum):
"""A string enum representing the account status."""

ACTIVE = "active"
UNVERIFIED = "unverified"
DEACTIVATED = "deactivated"


class Person(Entry):
"""A model that describes an individual and their digital identities."""

Expand All @@ -108,6 +116,9 @@ class Person(Entry):
managers: Optional[List[PyObjectId]]
"""A list of user IDs that can manage this person's items."""

account_status: AccountStatus = Field(AccountStatus.UNVERIFIED)
"""The status of the user's account."""

@validator("type", pre=True, always=True)
def add_missing_type(cls, v):
"""Fill in missing `type` field if not provided."""
Expand Down
5 changes: 5 additions & 0 deletions pydatalab/pydatalab/routes/v0_1/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ def save_user(user_id):

display_name: str | None = None
contact_email: str | None = None
account_status: str | None = None

if request_json is not None:
display_name = request_json.get("display_name", False)
contact_email = request_json.get("contact_email", False)
account_status = request_json.get("account_status", None)

if not current_user.is_authenticated and not CONFIG.TESTING:
return (jsonify({"status": "error", "message": "No user authenticated."}), 401)
Expand All @@ -41,6 +43,9 @@ def save_user(user_id):
else:
update["contact_email"] = EmailStr(contact_email)

if account_status:
update["account_status"] = account_status

except ValueError as e:
return jsonify(
{"status": "error", "message": f"Invalid display name or email was passed: {str(e)}"}
Expand Down
18 changes: 18 additions & 0 deletions pydatalab/schemas/cell.json
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,16 @@
"name"
]
},
"AccountStatus": {
"title": "AccountStatus",
"description": "A string enum representing the account status.",
"enum": [
"active",
"unverified",
"deactivated"
],
"type": "string"
},
"Person": {
"title": "Person",
"description": "A model that describes an individual and their digital identities.",
Expand Down Expand Up @@ -348,6 +358,14 @@
"items": {
"type": "string"
}
},
"account_status": {
"default": "unverified",
"allOf": [
{
"$ref": "#/definitions/AccountStatus"
}
]
}
}
},
Expand Down
18 changes: 18 additions & 0 deletions pydatalab/schemas/equipment.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,16 @@
"name"
]
},
"AccountStatus": {
"title": "AccountStatus",
"description": "A string enum representing the account status.",
"enum": [
"active",
"unverified",
"deactivated"
],
"type": "string"
},
"Person": {
"title": "Person",
"description": "A model that describes an individual and their digital identities.",
Expand Down Expand Up @@ -303,6 +313,14 @@
"items": {
"type": "string"
}
},
"account_status": {
"default": "unverified",
"allOf": [
{
"$ref": "#/definitions/AccountStatus"
}
]
}
}
},
Expand Down
18 changes: 18 additions & 0 deletions pydatalab/schemas/sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,16 @@
"name"
]
},
"AccountStatus": {
"title": "AccountStatus",
"description": "A string enum representing the account status.",
"enum": [
"active",
"unverified",
"deactivated"
],
"type": "string"
},
"Person": {
"title": "Person",
"description": "A model that describes an individual and their digital identities.",
Expand Down Expand Up @@ -307,6 +317,14 @@
"items": {
"type": "string"
}
},
"account_status": {
"default": "unverified",
"allOf": [
{
"$ref": "#/definitions/AccountStatus"
}
]
}
}
},
Expand Down
18 changes: 18 additions & 0 deletions pydatalab/schemas/startingmaterial.json
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@
"name"
]
},
"AccountStatus": {
"title": "AccountStatus",
"description": "A string enum representing the account status.",
"enum": [
"active",
"unverified",
"deactivated"
],
"type": "string"
},
"Person": {
"title": "Person",
"description": "A model that describes an individual and their digital identities.",
Expand Down Expand Up @@ -361,6 +371,14 @@
"items": {
"type": "string"
}
},
"account_status": {
"default": "unverified",
"allOf": [
{
"$ref": "#/definitions/AccountStatus"
}
]
}
}
},
Expand Down
1 change: 0 additions & 1 deletion webapp/src/components/Navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
<router-link to="/collections">Collections</router-link> |
<router-link to="/starting-materials">Inventory</router-link> |
<router-link to="/equipment">Equipment</router-link> |

<router-link to="/item-graph"
><font-awesome-icon icon="project-diagram" />&nbsp;Graph View</router-link
>
Expand Down
61 changes: 55 additions & 6 deletions webapp/src/components/UserTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Role</th>
<th scope="col">Verified</th>
<th scope="col">Status</th>
<th scope="col">Change status</th>
</tr>
</thead>
<tbody>
Expand All @@ -24,18 +25,47 @@
</select>
</td>
<td align="left">
<select v-model="test">
<option value="verified">Verified</option>
<option value="unverified">Unverified</option>
</select>
<button v-if="user.account_status === 'active'" class="btn btn-success btn-sm">
Active
</button>
<button v-else-if="user.account_status === 'unverified'" class="btn btn-warning btn-sm">
Unverified
</button>
<button v-else-if="user.account_status === 'deactivated'" class="btn btn-danger btn-sm">
Deactivated
</button>
</td>

<td align="left">
<button
v-if="user.account_status === 'active'"
class="btn btn-danger btn-sm"
@click="confirmUpdateUserStatus(user._id.$oid, 'deactivated')"
>
Deactivate
</button>
<button
v-else-if="user.account_status === 'unverified'"
class="btn btn-success btn-sm"
@click="confirmUpdateUserStatus(user._id.$oid, 'active')"
>
Activate
</button>
<button
v-else-if="user.account_status === 'deactivated'"
class="btn btn-success btn-sm"
@click="confirmUpdateUserStatus(user._id.$oid, 'active')"
>
Activate
</button>
</td>
</tr>
</tbody>
</table>
</template>

<script>
import { getUsersList, saveRole } from "@/server_fetch_utils.js";
import { getUsersList, saveRole, saveUser } from "@/server_fetch_utils.js";
export default {
data() {
Expand Down Expand Up @@ -74,10 +104,29 @@ export default {
this.users.find((user) => user._id.$oid === user_id).role = originalCurrentUser.role;
}
},
async confirmUpdateUserStatus(user_id, new_status) {
const originalCurrentUser = this.original_users.find((user) => user._id.$oid === user_id);
const currentUser = this.users.find((user) => user._id.$oid === user_id);
if (
window.confirm(
`Are you sure you want to change ${originalCurrentUser.display_name}'s status from "${originalCurrentUser.account_status}" to "${new_status}" ?`,
)
) {
await this.updateUserStatus(user_id, new_status);
currentUser.account_status = new_status;
} else {
this.users.find((user) => user._id.$oid === user_id).account_status =
originalCurrentUser.account_status;
}
},
async updateUserRole(user_id, user_role) {
await saveRole(user_id, { role: user_role });
this.original_users = JSON.parse(JSON.stringify(this.users));
},
async updateUserStatus(user_id, status) {
await saveUser(user_id, { account_status: status });
},
},
created() {
this.getUsers();
Expand Down

0 comments on commit bc4a393

Please sign in to comment.