Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/324 implement update locations #620

Merged
merged 49 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
6b45498
Updated changelog
brendan-oconnell Jul 11, 2024
c34531a
Fix merge conflict with changelog
brendan-oconnell Jul 12, 2024
467856e
Merge branch 'develop' into feature/324_implement_update_locations
brendan-oconnell Aug 2, 2024
cc9425f
location.rs merging example from publication.rs with new_location.rs
brendan-oconnell Aug 2, 2024
dc93225
Moved changes to location.rs to be discarded to untracked file
brendan-oconnell Aug 5, 2024
c0e5e30
Added logic for edit locations, following model of contributions_form.rs
brendan-oconnell Aug 5, 2024
24f9188
Fixed labels on modal form for Add location vs. edit location
brendan-oconnell Aug 5, 2024
9a2283a
Moved Edit and Delete buttons next to each other
brendan-oconnell Aug 6, 2024
cd4633e
Commented out canonical validation, added logic to make modal blank w…
brendan-oconnell Aug 9, 2024
bd6e804
Working on default values for Add new location
brendan-oconnell Aug 19, 2024
f3b0836
Fix formatter errors
brendan-oconnell Aug 26, 2024
184654c
Fixed description in changelog, added comment to model.rs
brendan-oconnell Aug 26, 2024
b3985fe
Merge branch 'develop' into feature/324_implement_update_locations
brendan-oconnell Aug 26, 2024
ce3cac4
Put single canonical location check back in place
brendan-oconnell Aug 26, 2024
0a80c7a
Temporarily hardcoded canonical location switch to test connection.tr…
brendan-oconnell Sep 4, 2024
7ea017c
Test changing canonical location with hardcoded data
brendan-oconnell Sep 4, 2024
3c3bd58
Merge branch 'develop' into feature/324_implement_update_locations
brendan-oconnell Sep 4, 2024
000ef5b
Deleted old comments and test code
brendan-oconnell Sep 5, 2024
1b52492
Working logic for switching canonical location
brendan-oconnell Sep 6, 2024
fe20b74
Delete comments in update_location function
brendan-oconnell Sep 6, 2024
e023750
Merge branch 'develop' into feature/324_implement_update_locations
brendan-oconnell Sep 6, 2024
a942a72
Add comments
brendan-oconnell Sep 6, 2024
0855c31
Update logic for changing canonical location
brendan-oconnell Sep 9, 2024
b37e035
Refactored for explicit location returns
brendan-oconnell Sep 10, 2024
db00825
testing loop to set non-canonical locations to canonical: false
brendan-oconnell Sep 11, 2024
678ff91
Change callbacks
brendan-oconnell Sep 11, 2024
e300823
Update changelog, remove minor comments
brendan-oconnell Sep 11, 2024
0be6440
Refactored canonical location
brendan-oconnell Sep 13, 2024
3f4385c
Refactor finding canonical location
brendan-oconnell Sep 16, 2024
af41779
Fix formatter errors, delete unused variables
brendan-oconnell Sep 17, 2024
6d596c9
Merge with develop
brendan-oconnell Sep 17, 2024
338130a
Fixed minor errors requiring a result, added allow dead_code to graph…
brendan-oconnell Sep 18, 2024
548d623
Fix changelog
brendan-oconnell Sep 20, 2024
5b6f4a0
Refactor to move database actions out of model.rs and into location/c…
brendan-oconnell Sep 23, 2024
363d913
Simplify logic for canonical/non-canonical updates and which update t…
brendan-oconnell Sep 23, 2024
9c954bb
Removed unnecessary if/let statements
brendan-oconnell Sep 23, 2024
8155b1c
Refactored update_canonical_location into impl Location in crud.rs
brendan-oconnell Sep 24, 2024
92e2085
Latest changes
brendan-oconnell Sep 25, 2024
15553fb
Merge remote-tracking branch 'refs/remotes/origin/feature/324_impleme…
brendan-oconnell Sep 25, 2024
d0e9ea5
Refactored update_canonical_location into update function in crud
brendan-oconnell Sep 25, 2024
200611f
Added createdAt and updatedAt back in, resolving the display error
brendan-oconnell Sep 25, 2024
603c38d
Fix formatter and clippy errors
brendan-oconnell Sep 25, 2024
f060526
Cleaned up comments
brendan-oconnell Sep 26, 2024
f94a397
Refactored let mut connection = db.get()?;, remove #[allow(dead_code)]
brendan-oconnell Sep 26, 2024
301cadf
store diesel.update results in a variable, update_result, and match a…
brendan-oconnell Sep 26, 2024
fbbbd3b
Merge branch 'develop' into feature/324_implement_update_locations
brendan-oconnell Sep 26, 2024
961d4e9
Refactoring based on suggestions from review
brendan-oconnell Oct 3, 2024
7f912b6
Merge branch 'develop' into feature/324_implement_update_locations
brendan-oconnell Oct 3, 2024
cc437b5
Fix changelog
brendan-oconnell Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed
- [565](https://github.com/thoth-pub/thoth/issues/565) - Don't generate Crossref metadata output if no DOIs (work or chapter) are present
- [324](https://github.com/thoth-pub/thoth/issues/324) - Make Locations editable, including the ability to change the Canonical Location for a Publication.

## [[0.12.9]](https://github.com/thoth-pub/thoth/releases/tag/v0.12.9) - 2024-09-06
### Added
Expand Down
7 changes: 0 additions & 7 deletions thoth-api/src/graphql/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1984,13 +1984,6 @@ impl MutationRoot {
)?)?;
}

if data.canonical != location.canonical {
// Each publication must have exactly one canonical location.
// Updating an existing location would always violate this,
// as it should always result in either zero or two canonical locations.
return Err(ThothError::CanonicalLocationError.into());
}

if data.canonical {
data.canonical_record_complete(&context.db)?;
}
Expand Down
109 changes: 106 additions & 3 deletions thoth-api/src/model/location/crud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use super::{
Location, LocationField, LocationHistory, LocationOrderBy, LocationPlatform, NewLocation,
NewLocationHistory, PatchLocation,
};
use crate::db_insert;
use crate::graphql::utils::Direction;
use crate::model::{Crud, DbInsert, HistoryEntry};
use crate::schema::{location, location_history};
use crate::{crud_methods, db_insert};
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
use diesel::{Connection, ExpressionMethods, QueryDsl, RunQueryDsl};
use thoth_errors::{ThothError, ThothResult};
use uuid::Uuid;

Expand Down Expand Up @@ -126,7 +126,98 @@ impl Crud for Location {
crate::model::publication::Publication::from_id(db, &self.publication_id)?.publisher_id(db)
}

crud_methods!(location::table, location::dsl::location);
// `crud_methods!` cannot be used for update(), because we need to execute multiple statements
// in the same transaction for changing a non-canonical location to canonical.
// These functions recreate the `crud_methods!` logic.
fn from_id(db: &crate::db::PgPool, entity_id: &Uuid) -> ThothResult<Self> {
let mut connection = db.get()?;
match location::table
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved
.find(entity_id)
.get_result::<Self>(&mut connection)
{
Ok(t) => Ok(t),
Err(e) => Err(ThothError::from(e)),
}
}

fn create(db: &crate::db::PgPool, data: &NewLocation) -> ThothResult<Self> {
let mut connection = db.get()?;
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved

connection.transaction(|connection| {
diesel::insert_into(location::table)
.values(data)
.get_result::<Self>(connection)
.map_err(|e| e.into())
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved
})
}

fn update(
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved
&self,
db: &crate::db::PgPool,
data: &PatchLocation,
account_id: &Uuid,
) -> ThothResult<Self> {
let mut connection = db.get()?;
let update_result: Result<Self, ThothError>;
// if changes to a location don't change its canonical or non-canonical status, only update that location.
if data.canonical == self.canonical {
update_result = connection.transaction(|connection| {
diesel::update(location::table.find(&self.location_id))
.set(data)
.get_result::<Self>(connection)
.map_err(ThothError::from)
});
// trying to change canonical location to non-canonical results in error.
} else if self.canonical && (data.canonical != self.canonical) {
return Err(ThothError::CanonicalLocationError);
// if user changes a non-canonical location to canonical, perform two simultaneous updates:
// change the former canonical location to non-canonical, the former non-canonical location to canonical
} else {
let canonical_location = self.get_canonical_location(db).map_err(ThothError::from)?;
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved

let old_canonical_location = PatchLocation {
location_id: canonical_location.location_id,
publication_id: canonical_location.publication_id,
landing_page: canonical_location.landing_page.clone(),
full_text_url: canonical_location.full_text_url.clone(),
location_platform: canonical_location.location_platform.clone(),
canonical: false,
};
update_result = connection.transaction(|connection| {
// Update the currently canonical location to non-canonical
diesel::update(location::table.find(&old_canonical_location.location_id.clone()))
.set(old_canonical_location)
.execute(connection)?;
diesel::update(location::table.find(&self.location_id))
// Update the data from the currently non-canonical location to make it canonical,
// along with any other changes from PatchLocation
.set(data)
.get_result::<Self>(connection)
.map_err(ThothError::from)
});
}

match update_result {
Ok(l) => {
let mut connection = db.get()?;
match self.new_history_entry(account_id).insert(&mut connection) {
Ok(_) => Ok(l),
Err(e) => Err(e),
}
}
Err(e) => Err(e),
}
}

fn delete(self, db: &crate::db::PgPool) -> ThothResult<Self> {
let mut connection = db.get()?;
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved
connection.transaction(|connection| {
match diesel::delete(location::table.find(self.location_id)).execute(connection) {
Ok(_) => Ok(self),
Err(e) => Err(ThothError::from(e)),
}
})
}
}

impl HistoryEntry for Location {
Expand Down Expand Up @@ -181,6 +272,18 @@ impl NewLocation {
}
}

impl Location {
pub fn get_canonical_location(&self, db: &crate::db::PgPool) -> ThothResult<Location> {
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved
let mut connection = db.get()?;
let canonical_location = crate::schema::location::table
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved
.filter(crate::schema::location::publication_id.eq(self.publication_id))
.filter(crate::schema::location::canonical.eq(true))
.first::<Location>(&mut connection)
.expect("Error loading canonical location for publication");
Ok(canonical_location)
}
}

impl PatchLocation {
pub fn canonical_record_complete(&self, db: &crate::db::PgPool) -> ThothResult<()> {
location_canonical_record_complete(
Expand Down
Loading
Loading