IEEE.org     |     IEEE Xplore Digital Library     |     IEEE Standards     |     IEEE Spectrum     |     More Sites

Verified Commit 342ec282 authored by Emi Simpson's avatar Emi Simpson
Browse files

[new arch] Use name parameters for calling bound/mapped queries

parent cd0396a3
Pipeline #900 passed with stage
in 56 seconds
......@@ -60,9 +60,9 @@ def delete_source(req: Request) -> Outcomes | Query[Outcomes, Outcomes]:
# Delete the source
queries.DeleteSourceIfOwned(int(req.form['source_id']), req.user),
# If successful, rebuild projects.json
lambda _: (outcome.RebuildProjectsJson(),),
on_success=lambda _: (outcome.RebuildProjectsJson(),),
# Otherwise, just put out an error
lambda id: (outcome.Error(GenericAlert(), f"The source with id {id} doesn't exist, or you don't have permission to delete it"),)
on_error=lambda id: (outcome.Error(GenericAlert(), f"The source with id {id} doesn't exist, or you don't have permission to delete it"),)
)
except ValueError:
# If the `source_id` was malformed, do an error
......@@ -118,10 +118,10 @@ def add_source(req: Request, pid: UncheckedPID, user: UserID) -> Outcomes | Quer
# Then actually start building the query
return queries.BoundQuery(
validate_and_fetch_pid(pid, user), # first we check that the user has permissions
lambda project: queries.MappedQuery( # if so...
transformation=lambda project: queries.MappedQuery( # if so...
# add a source to the project
queries.AddSourceToProject(project.project_id, source_type, source_url),
lambda source_id: \
on_success=lambda source_id: \
# then rebuild the projects.json file
[outcome.RebuildProjectsJson()
# and submit a new job for scanning this specific source
......@@ -133,7 +133,7 @@ def add_source(req: Request, pid: UncheckedPID, user: UserID) -> Outcomes | Quer
if project.draft_owner is None else
[],
# if there was a problem adding the source, turn it into an error
lambda e: ({
on_error=lambda e: ({
# this shouldn't be possible, because we validated that the project
# existed in the last step
queries.AddSourceError.NonexistantProject: outcome.Error(
......@@ -162,11 +162,11 @@ def add_owner(req: Request, pid: UncheckedPID, user: UserID) -> Outcomes | Query
# start building the query
return queries.BoundQuery(
validate_pid(pid, user), # first validate that the user owns this project
lambda project_id: queries.MappedQuery(
transformation=lambda project_id: queries.MappedQuery(
# then add the new owner
queries.AddOwnerByUsername(req.form['new_owner'], project_id),
lambda _: tuple(), # nothing needs to happen if we succeed
lambda error: ({ # if we fail, pick decipher the error by picking 1
on_success=lambda _: tuple(), # nothing needs to happen if we succeed
on_error=lambda error: ({ # if we fail, pick decipher the error by picking 1
# This shouldn't be possible, since we validated the project already
queries.AddOwnerError.NonexistantProject: outcome.Error(
ProjectField(project_id, ProjectFieldKind.AddOwner),
......@@ -212,7 +212,7 @@ def edit_properties(req: Request, pid: UncheckedPID, user: UserID) -> Outcomes |
return queries.BoundQuery(
validate_and_fetch_pid(pid, user), # Check that the user owns the project
lambda project_info: queries.BoundQuery(
transformation=lambda project_info: queries.BoundQuery(
# if so...
queries.MappedQuery(
# Update the project's properties with the new values
......@@ -221,9 +221,9 @@ def edit_properties(req: Request, pid: UncheckedPID, user: UserID) -> Outcomes |
*[f if len(f) > 0 else None for f in (slug, name, desc)]),
# If that succeeds, check whether or not the project was a draft that is
# now finalized
lambda is_final: is_final and project_info.draft_owner is not None,
on_success=lambda is_final: is_final and project_info.draft_owner is not None,
# If there was an error, decode it
lambda error: {
on_error=lambda error: {
# We already checked that the project exists, so this just means no
# change happened. We can report the errors for missing fields and
# nothing else
......@@ -235,13 +235,13 @@ def edit_properties(req: Request, pid: UncheckedPID, user: UserID) -> Outcomes |
"It looks like this URL is already taken!"
)] + missing_fields,
}[error]),
lambda needs_rescan:
transformation=lambda needs_rescan:
# If updating the project properties succeeded, do one of two things:
# If the project was a draft that was just finalized, we need to scan it
queries.MappedQuery(
# So get a list of the project's sources
queries.GetSources(project_info.project_id),
lambda sources: (
on_success=lambda sources: (
# rebuild the projects.json
outcome.RebuildProjectsJson(),
# and then request that all those sources be rebuilt
......@@ -254,7 +254,7 @@ def edit_properties(req: Request, pid: UncheckedPID, user: UserID) -> Outcomes |
e_source
for source in sources
for e_source in source.expand_source()]))),
lambda noreturn: noreturn) # impossible
on_error=lambda noreturn: noreturn) # impossible
if needs_rescan else
# If the project wasn't just finalized, we don't need to do anything but
# report the missing fields
......@@ -278,11 +278,11 @@ def remove_owner(req: Request, pid: UncheckedPID, user: UserID) -> Outcomes | Qu
return (outcome.Error(GenericAlert(), str(e)),)
# If the ID was retrieved successfully, start describing the query
return queries.BoundQuery(validate_pid(pid, user), # check the user owns this project
lambda pid: queries.MappedQuery(
transformation=lambda pid: queries.MappedQuery(
# if so, remove the attached owner
queries.RemoveOwner(pid, owner),
lambda _: tuple(), # if it succeeded, nothing else needs to happen
lambda _: (outcome.Error(
on_success=lambda _: tuple(), # if it succeeded, nothing else needs to happen
on_error=lambda _: (outcome.Error(
# otherwise, this indicates that the mentioned account isn't an owner
ProjectField(pid, ProjectFieldKind.Generic),
"That user is not an owner of this project"),)))
......@@ -294,11 +294,11 @@ def delete_project(_: Request, pid: UncheckedPID, user: UserID) -> Outcomes | Qu
Use with :meth:`auth_action()`
"""
return queries.BoundQuery(validate_pid(pid, user), # validate ownership
lambda pid: queries.MappedQuery(
transformation=lambda pid: queries.MappedQuery(
queries.DeleteProject(pid), # try to delete the project
lambda _: tuple(), # success - nothing needs to change
on_success=lambda _: tuple(), # success - nothing needs to change
# error - should be impossible due to the above validation
lambda _: (outcome.Error(ProjectField(pid, ProjectFieldKind.Generic),
on_error=lambda _: (outcome.Error(ProjectField(pid, ProjectFieldKind.Generic),
"[INTERNAL ERROR] This project does not exist"),)))
def set_high_contrast(req: Request) -> Outcomes:
......@@ -357,9 +357,9 @@ def validate_pid(project_id: UncheckedPID, user_id: UserID) -> Query[ProjectID,
return queries.MappedQuery(
# Check that we own the project
queries.ValidateProjectOwned(project_id, user_id),
lambda pid: pid, # Pass through the ID on a success
on_success=lambda pid: pid, # Pass through the ID on a success
# But if we don't own it or it doesn't exist, stop execution with an error
lambda _: (outcome.Error(GenericAlert(), "Either you don't own this project, or it doesn't exist"
on_error=lambda _: (outcome.Error(GenericAlert(), "Either you don't own this project, or it doesn't exist"
),)
)
def validate_and_fetch_pid(project_id: UncheckedPID, user_id: UserID) -> Query[ProjectInfo, Tuple[outcome.Error]]:
......@@ -369,9 +369,9 @@ def validate_and_fetch_pid(project_id: UncheckedPID, user_id: UserID) -> Query[P
return queries.MappedQuery(
# Check that we own the project
queries.RetreiveProjectInfoIfOwned(project_id, user_id),
lambda info: info, # Pass through project info if we succeed
on_success=lambda info: info, # Pass through project info if we succeed
# Or else halt execution with an error
lambda _: (outcome.Error(GenericAlert(), "Either you don't own this project, or it doesn't exist"),))
on_error=lambda _: (outcome.Error(GenericAlert(), "Either you don't own this project, or it doesn't exist"),))
#class RemoveOwner(Action): pass
#class Edit(Action): pass
......
......@@ -408,18 +408,18 @@ class MappedQuery(Generic[Q1, Q2, E1, E2]):
function will never run. Keep that in mind!
"""
query: Query[Q1, E1]
s_transformation: Callable[[Q1], Q2]
e_transformation: Callable[[E1], E2]
on_success: Callable[[Q1], Q2]
on_error: Callable[[E1], E2]
def get_query(self) -> QueryRequest:
return self.query.get_query()
def handle_results(self, results: QueryResult | SqlIntegrityError) -> Finished[Q2] | Error[E2] | Unfinished[Q2, E2]:
handled = self.query.handle_results(results)
if isinstance(handled, Finished):
return Finished(self.s_transformation(handled.value))
return Finished(self.on_success(handled.value))
elif isinstance(handled, Error):
return Error(self.e_transformation(handled.value))
return Error(self.on_error(handled.value))
else:
return Unfinished(MappedQuery(handled.next_query, self.s_transformation, self.e_transformation))
return Unfinished(MappedQuery(handled.next_query, self.on_success, self.on_error))
## Practical Queries
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment