Orchard cms get latest version of content item even if it removed - orchardcms

I'm using Orchard 1.7
In Orchard, when a content item is removed, it don't actually deleted from database, the cms just only set Published & Latest value of all versions of content item to 0, it still can be retrieved
And my problem is: I have a user that was removed (this user was modified many times, especially the Title)
Case 1: I use cms.Get(userId, VersionOptions.AllVersions).As<TitlePart>()
Case 2: I use myItem.As<CommonPart>().Owner.As<TitlePart>()
And the result is it always returns the title of the first version of this user, I want it return the latest version (the largest version number) of it.
So, where in Orchard should I modify to resolve this ?

I had this issue too. Here is my solution to query the recent version of a deleted user by using the content manager:
Orchard.Users.Models.UserPart lUserPart = mContentManager
.Query<Orchard.Users.Models.UserPart,
Orchard.Users.Models.UserPartRecord>(VersionOptions.AllVersions)
.Where(u => u.NormalizedUserName == lowerName) // taken from Orchard.Users.Services.MembershipService.GetUser()
.List()
.LastOrDefault(); // LastOrDefault() to get version with highest version number

Related

Validate #versionColumn value before saving an entity with TypeORM

I'm currently working on saving data in a postgres DB using TypeORM with the NestJS integration. I'm saving data which keeps track of a version property using TypeORM's #VersionColumn feature, which increments a number each time save() is called on a repository.
For my feature it is important to check this version number before updating the records.
Important
I know I could technically achieve this by retrieving the record before updating it and checking the versions, but this leaves a small window for errors. If a 2nd user updates the same record in that millisecond between the get and save or if it would take longer for some weird reason, it would up the version and make the data in the first call invalid. TypeORM doesn't check the version value, so even if a call has a lower value than what is in the database, it still saves the data eventhough it should be seen as out of date.
1: User A checks latest version => TypeORM gives back the latest version: 1
2: User B updates record => TypeORM ups the version: 2
3: User A saves their data with version 1 <-- This needs to validate the versions first.
4: TypeORM overwrites User B's record with User A's data
What I'm looking for is a way to make TypeORM decline step 3 as the latest version in the database is 2 and User A tries to save with version 1.
I've tried using the querybuilder and update statements to make this work, but the build-in #VersionColumn only up the version on every save() call from a repository or entity manager.
Besides this I also got a tip to look into database triggers, but as far as I could find, this feature is not yet supported by TypeORM
Here is an example of the setup:
async update(entity: Foo): Promise<boolean> {
const value = await this._configurationRepository.save(entity);
if (value === entity) {
return true;
}
return false;
}
In my opinion, something like this is much better served through triggers directly in the Database as it will fix concerns around race conditions as well as making it so that modifications made outside the ORM will also update the version number. Here is a SQL Fiddle demonstrating triggers in action. You'll just need to incorporate it into your schema migrations.
Here is the relevant DDL from the SQL Fiddle example:
CREATE TABLE entity_1
(
id serial PRIMARY KEY,
some_value text,
version int NOT NULL DEFAULT 1
);
CREATE OR REPLACE FUNCTION increment_version() RETURNS TRIGGER AS
$BODY$
BEGIN
NEW.version = NEW.version + 1;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER increment_entity_1_version
BEFORE UPDATE
ON entity_1
FOR EACH ROW
EXECUTE PROCEDURE increment_version();
The same trigger function can be used for any table that has a version column in case this is a pattern you want to use across multiple tables.
I think you are looking for concurrency control. If this is the case there is a solution in this about 1/2 the way down. TypeORM concurrency control issue

Is there a way to specify a "master" or "index" migration?

I'm working on an existing Django 2.2 application comprising a custom app in conjunction with a Wagtail CMS, where I'm iteratively adding new wagtail page-types in separate user stories over time.
I want to be able to create a "master" or "index" migration that pre-builds each page-type in the database automatically when migrations are run (ours are performed in an Ansible task upon deployment). As far as I can tell, what I need requires:
The auto-built migration that modifies the DB schema for each page
A further migration that is always run last and which contains a dependencies attr - able to be updated with a single list-entry representing the new page's migration name, each time one is added.
I can already auto-build page-types using the following logic in a create() method called from migrations.RunPython() but at the moment, this same page-build logic needs to exist in each page's migration - I'd prefer it if this existed in a single migration (or an alternative procedure if one exists in DJango) that can always be run.
Ideally, the page_types list below could be replaced by just iterating over BasePage.__subclasses__(), (Where all page-types inherit from BasePage) meaning this "master" migration need never be altered again.
Note: if it helps any, the project is still in development, so any solution that is slightly controversial or strictly "dev-only" is acceptable - assuming it can be made acceptable and therefore less controversial by merging migrations later.
...
...
# Fetch the pre-created, root Page"
root_page = BasePage.objects.all().first()
page_types = [
ManageAccountPage,
EditUserDetailPage,
]
path_init = int('000100020003') # The last value for `path` from 0007_initialise_site_ttm.py
# Create, then add all child pages
for page_type in page_types:
title_raw = page_type.__name__.replace('Page', '')
page = page_type(
title=utils.convert_camel_to_human(title_raw),
slug=title_raw.lower(),
show_in_menus='t',
content_type=ContentType.objects.get_for_model(page_type),
path=path_init + 1,
depth=2
)
try:
root_page.add_child(instance=page)
except exceptions.ValidationError:
continue
...
...
What's the problem?
(See "What I've tried" below)
What I've tried:
A custom pin_curr_migration() method called from migrations.RunPython() that deletes the "master" migration's own record in django_migrations allowing it to be re-run. This however, results in errors where DJango complains about previously built pages already existing.

How to set a category to a Liferay Web Content in Java?

In Liferay 7, I have a Web Content, a vocabulary and a category.
How to set the category to the Web Content?
I wrote this code:
article = JournalArticleLocalServiceUtil.addArticle(...);
category = AssetCategoryLocalServiceUtil.addCategory(...);
AssetCategoryLocalServiceUtil.setAssetEntryAssetCategories(
article.getPrimaryKey(), new long[]{category.getPrimaryKey()});
At execution no error, but the category does not show up on the edit page of the created Web Content:
The category has been created successfully, but the Web Content does not get that category assigned.
What am I doing wrong?
I have also tried addAssetEntryAssetCategories, addAssetEntryAssetCategory, addAssetCategoryAssetEntry: same problem.
Try using any of these 2 functions to add category:
addAssetEntryAssetCategory(long entryId, long categoryId);
addAssetEntryAssetCategories(long entryId, long[] categoryIds);
In your code, you are using primary_key, however, as per documentation you should be using entry id and category id. So your function call should look like this:
AssetEntry entry = AssetEntryLocalServiceUtil.fetchEntry(JournalArticle.class.getName(), article.getResourcePrimKey());
AssetCategoryLocalServiceUtil.addAssetEntryAssetCategory(
entry.getEntryId(), category.getCategoryId());
Since 7.0, they removed the getEntryId method from JournalArticle you would need an additional call to fetch it. There is a update method which you may also consider that would do this in single call. I'm still using 6.2 and catching up 7 :).
Please note categories are designed for use by administrators, not regular users.
I am using liferay 7.1 dxp
In my case I have to update category of journal article or web content using program.
In order to achieve this I have to use assetEntryAssetCategoryRel class.
to access this and related class first I added dependency to my build.gradle file
compileOnly group: "com.liferay", name: "com.liferay.asset.entry.rel.api", version: "1.1.0"
List<AssetEntryAssetCategoryRel> assetEntryAssetCategoryRelsByAssetEntryId = AssetEntryAssetCategoryRelLocalServiceUtil.
getAssetEntryAssetCategoryRelsByAssetEntryId(assetEntry.getEntryId());
if(assetEntryAssetCategoryRelsByAssetEntryId!=null && !assetEntryAssetCategoryRelsByAssetEntryId.isEmpty()){
AssetEntryAssetCategoryRel assetEntryAssetCategoryRel = assetEntryAssetCategoryRelsByAssetEntryId.get(0);
assetEntryAssetCategoryRel.setAssetCategoryId(assetCategory.getCategoryId());
assetEntryAssetCategoryRel = AssetEntryAssetCategoryRelLocalServiceUtil.updateAssetEntryAssetCategoryRel(assetEntryAssetCategoryRel);
}
I had assetentry and assetcategory object
This works fine for me

Overwrite Major Version Using Object Model

I have versioning and checkin/checkout enabled in a SharePoint 2010 list, and for business-related reasons, would like to update information in a field: overwriting the field data for all versions in a similar manner and in place so that the version numbers do not change.
If I call SPListItemVersion.ListItem.UpdateOverwriteVersion(), it fails stating that I need to check out the item before making changes to it. Makes sense. So I precede the update statement with SPListItemVersion.ListItem.CheckOut() statement, attempt the update, and receive an error that I cannot overwrite a published version. I've also attempted to precede the check out with SPSite.AllowUnsafeUpdates = true, setting it back to false after the update call, but the latter error still occurs. Any ideas?
Stripped code below:
foreach (SPListItemVersion itemVersion in item.Versions){
itemVersion.ListItem.File.CheckOut(SPFile.SPCheckOutType.Online, itemVersion.ListItem.File.TimeLastModified.ToString());
site.AllowUnsafeUpdates = true;
itemVersion.ListItem["FieldName"] = "changed value here";
itemVersion.ListItem.UpdateOverwriteVersion();
site.AllowUnsafeUpdates = false;
itemVersion.ListItem.File.CheckIn("Updated list item version", SPCheckinType.OverwriteCheckIn);
}
To anyone that may find themselves facing this issue, you do not need to toggle the AllowUnsafeUpdates field. What worked for me is replacing the itemVersion.ListItem.UpdateOverwriteVersion() statement with itemVersion.ListItem.SystemUpdate(false). The parameter passed in tells SharePoint to not create a new version when updating.
Edit: This answer only updates the current item again. SPListItemVersion field references are available via a get only; it appears this is not possible in the object model.

Umbraco - Examine index not updated

I am using Umbraco CMS, and trying to use its site search function that uses Examine.
When I edit a page and publish it, the examine index is not updated, hence search results are always out of date. I have to manually delete the Index folder to update it.
Shouldn't the index be updated automatically everytime you update the content?
I wrote a class that updates the index on publish.
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.web;
using Examine;
public class UmbracoEvents: ApplicationBase
{
/// <summary>Constructor</summary>
public UmbracoEvents()
{
Document.AfterPublish += new Document.PublishEventHandler(Document_AfterPublish);
}
private void Document_AfterPublish(Document sender, umbraco.cms.businesslogic.PublishEventArgs e)
{
// Rebuild SiteSearchIndexer
ExamineManager.Instance.IndexProviderCollection["SiteSearchIndexer"].RebuildIndex(); // Unfortunately this doesn't index the latest change, must republish to index it
}
}
However it doesn't get the latest change even if it is supposed to run "after" publish. So, to make the search results up to date, you have to publish twice :S
You can manually update the index by using Examine Dashboard.
To automatically rebuild indexes on app startup, you could add this line into ExamineIndex.config located in config directory
<Examine RebuildOnAppStart="true">
Indexes should rebuild automatically when you publish/republish a content node. If it doesn't work, you may have configuration problem with Examine.

Resources