How to recover deleted data in alfresco share through java? - spring

I am new to alfresco community and i am using alfresco community for Document Management System.
Now my problem is i have deleted one document like as shown below and now i want to recover that data into same in which folder that exist before deletion
Document document = (Document) session.getObjectByPath(filePath);
document.delete();
Please any body help me...

You can use this:
nodeArchiveService.restoreArchivedNode(NodeRef archivedNodeRef)
To get the archivedNodeRef you can either search it in alfresco database (bad) find it using one of it property under the archive://SpacesStore
new NodeRef(archiveRoot.getStoreRef(),(String)node.get("UUID"))
http://dev.alfresco.com/resource/docs/java/org/alfresco/repo/node/archive/NodeArchiveService.html
If you have the trashcanCleaner up and running, your trashcan is protected 14d by default after that, the node is removed.
An sql query to get node from archive store:
String sql = "SELECT n.id, n.UUID "
+ "FROM alf_node n, alf_store s "
+ "WHERE n.store_id = s.id "
+ "AND s.protocol = 'archive' "
+ "AND n.AUDIT_MODIFIED is not null "
+ "ORDER BY n.id asc ";
Add a few criteria in the where clause on the ALF_NODE_PROPERTIES table and you are set.

You can use the java api VersionService(restore), if you know the deleted node.
http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/deleted-nodes/{id}/restore
restore
#Auditable(parameters={
"nodeRef",
"parentNodeRef",
"assocTypeQName",
"assocQName"
})
NodeRef restore(NodeRef nodeRef,
NodeRef parentNodeRef,
QName assocTypeQName,
QName assocQName)
By default a deep restore is performed.
Parameters:
nodeRef - the node reference to a node that no longer exists in the store
parentNodeRef - the new parent of the restored node
assocTypeQName - the assoc type qname
assocQName - the assoc qname
Returns:
the newly restored node reference

Also, if your node had "sys:temporary" aspect applied, then you are out of luck, that's the equivalent of "shift + delete" in Windows. You could still get it's content from the deleted store on disk, though.
Take a look at this blog post to understand the complete process:
https://blyx.com/2014/08/18/understanding-alfresco-content-deletion/

Related

Fetch absolute or relative path using file object in IBM filenet

String mySQLString = "select * from document where documentTitle like '%test%' ";
SearchSQL sql = new SearchSQL(mySQLString);
IndependentObjectSet s = search.fetchObjects(sql, 10, null, true);
Document doc;
PageIterator iterator = s.pageIterator();
iterator.nextPage();
for (Object object : iterator.getCurrentPage()) {
doc = (Document) object;
Properties properties = doc.getProperties();
//I am trying to get an absolute or relative path here for every document.
// for eg: /objectstorename/foldername/filename like this.
}
I have tried searching propeties and class descriptions in document . but can't able to find the path. ?
To do it all in one single query (as you are trying to do in your code) you can create a join with the ReferentialContainmentRelationship table. The property Head of this table points to the document, the property Tail points to the folder the document is filled in and the property ContainmentName is the name the document has in the folder. Use the following code to construct the document path:
SearchSQL searchSQL = new SearchSQL("SELECT R.ContainmentName, R.Tail, D.This FROM Document AS D WITH INCLUDESUBCLASSES INNER JOIN ReferentialContainmentRelationship AS R WITH INCLUDESUBCLASSES ON D.This = R.Head WHERE DocumentTitle like '%test%'");
SearchScope searchScope = new SearchScope(objectStore);
RepositoryRowSet objects = searchScope.fetchRows(searchSQL, null, null, null);
Iterator<RepositoryRow> iterator = objects.iterator();
while (iterator.hasNext()) {
RepositoryRow repositoryRow = iterator.next();
Properties properties = repositoryRow.getProperties();
Folder folder = (Folder) properties.get("Tail").getEngineObjectValue();
String containmentName = properties.get("ContainmentName").getStringValue();
System.out.println(folder.get_PathName() + "/" + containmentName);
}
Paths constructed this way can also be used to fetch the object from the object store. The query code can be optimized by using a property filter as the third argument of the fetchRows() method. Don't know how this behaves if the document is filed in multiple folders.
I suggest you explore the "Creating DynamicReferentialContainmentRelationship Objects" section of FileNet documentation:
https://www.ibm.com/support/knowledgecenter/SSNW2F_5.5.0/com.ibm.p8.ce.dev.ce.doc/containment_procedures.htm#containment_procedures__fldr_creating_a_drcr
A FileNet Ddocument can be assigned to multiple Folders, so you can have several logical "Paths" for a given document.
At end, you should get something like "Folder.get_PathName() + DynamicReferentialContainmentRelationship.get_Name()" to display the full pathname.
As described by samples in FileNet documentation, a relationship object (e.g. DynamicReferentialContainmentRelationship) controls the relation of document/folder:
myRelationshipObject.set_Head(myDocument);
myRelationshipObject.set_Tail(myFolder);
Also, keep in mind that a FileNet Document can be also a "unfiled" document, so there is no actual "pathname" or folder "relationship" to be retrieved.
tl;dr from FileNet Content Engine - Database Table for Physical path
Documents are stored among the directories at the leaf level using a hashing algorithm to evenly distribute files among these leaf directories.

Dexie.js - table.delete(id) not working for per-row deletion

i'm just starting out with Dexie, and I seem to be coming unstuck.
I have a small database (less than 1000 rows), and i'm trying to delete each row one-by-one once I know that the row has been sent to a remote API.
I can also successfully save to the table (which is defined by an ID and a column storing a serialised object)
here's my code:
if (online) {
//we query the db and send each event
database.open()
let allEvents = database.events.toCollection()
let total = allEvents.count(function (count) {
console.log(count + ' events in total')
//a simple test to ensure we're seeing the right number of records
})
allEvents.each(function(thisEvent){
//push to remote API
console.log('deleting ' + thisEvent.id)
database.events.delete(thisEvent.id) //<= this doesn't seem to be working
})
}
All of this with the exception of the final delete statement.
Any ideas on how I should fix this? the important thing for me is to delete on a per-row basis.
thanks in advance!
I was experiencing the same problem, and the answer from Eugenia Pais wasn't working for me. So after some tests, I saw the trouble was with the type of the variable: I was using a string, but a number is needed, so this is how I solved it:
function removeRow (primaryKey) {
primaryKey = parseInt(primaryKey);
databaseName.tableName.where('primaryKey').equals(primaryKey).delete().then(function(deleteCount) {
console.log ("Deleted " + deleteCount + " rows");
}).catch(function(error) {
console.error ("Error: " + error);
});
So be aware you are using a number as argument.
The correct way to delete each row should be selecting the specific row and delete it:
database.tableName.where(indexId).equals(indexValue).delete();
The data type of the key is not a problem you could verify it in my example here: example
db.example.where('key').equals('one').delete();
Maybe you are trying to delete by a property that not is an index.

JCR query to return excerpt and parent identifier

I would like to query the jackrabbit repository on the versions I have stored.
My repository looks like the following:
Following xpath query works well://element(*, nt:frozenNode)[jcr:contains(., '" + keyword + "') ]/rep:excerpt(.) and from the Row object returned I can get the excerpt found in the de:template nodes 'de:content' property (for this to be full-text indexable I have my own lucene configuration).
The problem however is: how to know what elements excerpt is found for, since the query only returns me the path found (/jcr:system/jcr:versionStorage/95/c8/3e/95c83efc-8441-4017-b3af-ae7be49f07e5/1.0/jcr:frozenNode/de:template) and the excerpt itself.
So I would like to know the identifier of the nt:versionHistory node, as stored in Jackrabbit.
I have a solution for this as well, by getting the parent nodes until the nt:versionHistory is reached and getting its identifier:
Row row = (Row) rows.next();
Node node = row.getNode();
Node frozenNode = node.getParent();
Node versionNumber = frozenNode.getParent();
String versionId = versionNumber.getIdentifier();
However this takes too much time and with lots of versions its bad for the performance.
Therefore, I wonder if it's possible to include this version id in the query, such that no parent nodes need to be fetched after the query is executed.
That's probably not possible using an XPath Query. But you could do it using SQL2 using a join:
SELECT n.*, excerpt(n), v.[jcr:uuid]
FROM [nt:frozenNode] AS n
INNER JOIN [nt:version] AS v ON ISDESCENDANTNODE(n,v)
WHERE contains(n.*,'Adobe')

Set CRM Lookup Values with WebAPI

Who had done CRM Web API calls to update CRM entities with Lookup values from another Entity.
I'm trying to set a Lookup Value to another Entity within CRM using WebAPI, CRM 2016. It works if I disable the Lookup value but once I enable the Lookup value, I receive Bad Request.
Below is my code in LinqPad so it does work.
void Main()
{
using(var webClient = new WebClient()){
webClient.Credentials = new NetworkCredential("Username", "Password", "Domain");
webClient.Headers.Add("OData-MaxVersion", "4.0");
webClient.Headers.Add("OData-Version", "4.0");
webClient.Headers.Add("accept", "application/json");
webClient.Headers.Add("Content-Type","application/json");
webClient.Headers.Add("Prefer", "odata.include-annotations=*");
webClient.BaseAddress = "http://dev.company.com/DEV2016/api/data/v8.0/";
var JO = new JObject();
JO.Add("col_name","My Name");
//JO.Add("col_contactid#odata.bind","/contacts(7266f26b-7105-e611-811e-005056b61789)");
var dataString = JO.ToString();
var responseString = webClient.UploadString("col_advisors", "POST", dataString);
Console.WriteLine(webClient.ResponseHeaders.Get("OData-EntityId"));
}
}
Case matters with the WebAPI. Make sure your col_contactid is the schema name, not the logical name. For example, the logical name of your attribute is col_contactid (logical names are always lowercase), but schema names often times have upper case letters. Yours might be col_ContactId for example, in which case you would want to use col_ContactId#odata.bind.
The easiest way to find the schema name of your attribute is by going to CRM -> Settings -> Solutions -> your solution -> Entites (on the left) -> Advisors -> Fields. In that grid you'll see a column for schema name.
I got it to work. The fields really have to be unique as it is case sensitive. Comments here and also this blog, really helped.
http://inogic.com/blog/2016/02/set-values-of-all-data-types-using-web-api-in-dynamics-crm/
Step 1 : Goto Cutomization  Developer Resource.
Step 2 : Click to “Download Odata Metadata” link and Download the same.
Step 3 : Once Download, open it and find out name of lookup attribute ( i.e. new_qualifiedleadid) and check its casing.
Step 4 : Verify it with the value which you are setting in the code it should be same.
While my column was col_contactid, CRM renames the Navigational Column to be what was above col_ContactId.
I also used Postman(google chrome) plugin and added the following Header to my Post.
webClient.Headers.Add("Prefer", "odata.include-annotations=*");

Cannot specify child attributes in the columnset for Retrieve

In attempting to merge contacts in Microsoft CRM, I am using the following code -
//c1ID and c2ID are GUIDs of duplicated contacts.
EntityReference target = new EntityReference();
target.LogicalName = Contact.EntityLogicalName;
target.Id = c2ID;
MergeRequest merge = new MergeRequest();
// SubordinateId is the GUID of the account merging.
merge.SubordinateId = c1ID;
merge.Target = target;
merge.PerformParentingChecks = true;
Contact updater = new Contact();
Contact updater2 = new Contact();
updater = (Contact)xrmSvc.ContactSet.Where(c => c.ContactId.Equals(c1ID)).First();
updater2 = (Contact)xrmSvc.ContactSet.Where(c => c.ContactId.Equals(c2ID)).First();
MergeResponse mergedR = (MergeResponse)xrmSvc.Execute(merge);
When I try my Execute call here,I get this error -
Cannot specify child attributes in the columnset for Retrieve. Attribute: owneridname.
Am I not setting something correctly?
Having updatecontent does not change the issue. In fact, I get the error on lookups entered into the updatecontent. I find you have to build new entityreferences:
if (match.Contains("new_mostrecentcampaign"))
master["new_mostrecentcampaign"] =
new EntityReference(match.GetAttributeValue<EntityReference>("new_mostrecentcampaign").LogicalName
, match.GetAttributeValue<EntityReference>("new_mostrecentcampaign").Id);
...
Merge.UpdateContent = master
...
I realize this is a pretty old question, but for those of you who have run into the same issue in 2021 and beyond, here's the reason this error happens.
TL;DR: Ensure the EntityReference values for the attributes does not specify the Name property.
Explanation:
Everything that gets added to the Entity set to UpdateContent will be applied to the Target contact. When programmatically executing a MergeRequest within a plugin/workflow, the attributes of the UpdateContent get applied (as desired).
Where this breaks down is for EntityReference value types (lookups). The internal Microsoft code that performs this operation tries to interpret all properties of the EntityReference object, including Name.
So when the existing values from the SubordinateId contact are pulled using IOrganizationService.Retrieve (to dynamically get the latest version), the Name property is automatically set for those lookup attributes (the child record). This operation is not valid, even though it's not the user code that's directly executing it.
This brings us full circle to explain the original error:
Cannot specify child attributes in the columnset for Retrieve
I wish I had some documentation for this, but although the official documentation notes that the UpdateContent is optional, experience proves that it is in fact necessary. In the MergeRequests I've tested, I always include that property in the request, and there's a post in the MSDN forums for Dynamics 3.0 that suggests the same.
In fact, when I try to merge two contacts in my org without UpdateContent assigned, I actually get a FaultException saying the following:
Required field 'UpdateContent' is missing
Even though the documentation says it's optional!
So I'd suggest populating the UpdateContent property with something as in the below and see if that works:
var merge = new MergeRequest
{
// SubordinateId is the GUID of the account merging.
SubordinateId = c1ID,
Target = target,
PerformParentingChecks = true,
UpdateContent = new Contact()
};

Resources