private ENSessionFindNotesContext FindNotes_NextFindInLinkedScope(ENSessionFindNotesContext context) { if (context.linkedNotebooksToSearch.Count == 0) { context = FindNotes_ProcessResults(context); return context; } // Pull the first notebook off the list of pending linked notebooks. ENNotebook notebook = context.linkedNotebooksToSearch[0]; context.linkedNotebooksToSearch.RemoveAt(0); ENNoteStoreClient noteStore = NoteStoreForLinkedNotebook(notebook.LinkedNotebook); NoteFilter notefilter = context.noteFilter; if (notebook.IsJoinedPublic) { // https://dev.evernote.com/doc/reference/NoteStore.html#Fn_NoteStore_findNotesMetadata // to search joined public notebook, the auth token can be nil, but notebookGuid must be set notefilter.NotebookGuid = notebook.Guid; } try { List<NoteMetadata> notesMetadataList = noteStore.FindNotesMetadata(context.noteFilter, context.maxResults, context.resultSpec); context.findMetadataResults.AddRange(notesMetadataList); // Do it again with the next linked notebook in the list. context = FindNotes_NextFindInLinkedScope(context); } catch (Evernote.EDAM.Error.EDAMUserException) { } catch (Exception ex) { ENSDKLogger.ENSDKLogError(string.Format("findNotes: Failed to find notes (linked). Notebook = {0}; {1}", notebook, ex.Message)); throw new Exception(ex.Message, ex.InnerException); } return context; }
private ENSessionFindNotesContext FindNotes_ProcessResults(ENSessionFindNotesContext context) { // OK, now we have a complete list of note refs objects. If we need to do a local sort, then do so. if (context.order.HasFlag(SortOrder.RecentlyCreated)) { if (context.sortAscending) { context.findMetadataResults.Sort((x, y) => x.Created.CompareTo(y.Created)); } else { context.findMetadataResults.Sort((x, y) => y.Created.CompareTo(x.Created)); } } else if (context.order.HasFlag(SortOrder.RecentlyCreated)) { if (context.sortAscending) { context.findMetadataResults.Sort((x, y) => x.Updated.CompareTo(y.Updated)); } else { context.findMetadataResults.Sort((x, y) => y.Updated.CompareTo(x.Updated)); } } else { if (context.sortAscending) { context.findMetadataResults.Sort((x, y) => x.Title.CompareTo(y.Title)); } else { context.findMetadataResults.Sort((x, y) => y.Title.CompareTo(x.Title)); } } // Prepare a dictionary of all notebooks by GUID so lookup below is fast. Dictionary<string, ENNotebook> notebooksByGuid = null; if (context.scopeNotebook == null) { notebooksByGuid = new Dictionary<string, ENNotebook>(); foreach (ENNotebook notebook in context.allNotebooks) { notebooksByGuid[notebook.Guid] = notebook; } } // Turn the metadata list into a list of note refs. List<ENSessionFindNotesResult> findNotesResults = new List<ENSessionFindNotesResult>(); foreach (NoteMetadata metadata in context.findMetadataResults) { ENNoteRef @ref = new ENNoteRef(); @ref.Guid = metadata.Guid; // Figure out which notebook this note belongs to. (If there's a scope notebook, it always belongs to that one.) ENNotebook notebook = null; if (context.scopeNotebook != null) { notebook = context.scopeNotebook; } else { notebooksByGuid.TryGetValue(metadata.NotebookGuid, out notebook); } if (notebook == null) { // This is probably a business notebook that we haven't explicitly joined, so we don't have it in our list. if (!(context.resultGuidsFromBusiness.Contains(metadata.Guid))) { // Oh, it's not from the business. We really can't find it. This is an error. ENSDKLogger.ENSDKLogError(string.Format("Found note metadata but can't determine owning notebook by guid. Metadata = {0}", metadata)); } continue; } if (notebook.IsBusinessNotebook) { @ref.Type = ENNoteRef.ENNoteRefType.TypeBusiness; @ref.LinkedNotebook = ENLinkedNotebookRef.LinkedNotebookRefFromLinkedNotebook(notebook.LinkedNotebook); } else if (notebook.IsLinked) { @ref.Type = ENNoteRef.ENNoteRefType.TypeShared; @ref.LinkedNotebook = ENLinkedNotebookRef.LinkedNotebookRefFromLinkedNotebook(notebook.LinkedNotebook); } else { @ref.Type = ENNoteRef.ENNoteRefType.TypePersonal; } ENSessionFindNotesResult result = new ENSessionFindNotesResult(); result.NoteRef = @ref; result.Notebook = notebook; result.Title = metadata.Title; result.Created = metadata.Created.ToDateTime(); result.Updated = metadata.Updated.ToDateTime(); findNotesResults.Add(result); // If the caller specified a max result count, and we've reached it, then stop fixing up // results here. if (context.maxResults > 0 && findNotesResults.Count > context.maxResults) { break; } } context.results = findNotesResults; return context; }
private ENSessionFindNotesContext FindNotes_FindInLinkedScope(ENSessionFindNotesContext context) { // Skip linked scope if scope notebook is not a personal linked notebook, or if the // linked scope is not included. if (context.scopeNotebook != null) { if (!context.scopeNotebook.IsLinked || !context.scopeNotebook.IsBusinessNotebook) { context = FindNotes_ProcessResults(context); return context; } } else if (!(context.scope.HasFlag(SearchScope.PersonalLinked))) { context = FindNotes_ProcessResults(context); return context; } // Build a list of all the linked notebooks that we need to run the search against. context.linkedNotebooksToSearch = new List<ENNotebook>(); if (context.scopeNotebook != null) { context.linkedNotebooksToSearch.Add(context.scopeNotebook); } else { foreach (ENNotebook notebook in context.allNotebooks) { if (notebook.IsLinked && !notebook.IsBusinessNotebook) { context.linkedNotebooksToSearch.Add(notebook); } } } context = FindNotes_NextFindInLinkedScope(context); return context; }
private ENSessionFindNotesContext FindNotes_FindInBusinessScope(ENSessionFindNotesContext context) { // Skip the business scope if the user is not a business user, or the scope notebook // is not a business notebook, or the business scope is not included. if (!IsBusinessUser || (context.scopeNotebook != null && !context.scopeNotebook.IsBusinessNotebook) || (context.scopeNotebook == null && !(context.scope.HasFlag(SearchScope.Business)))) { context = FindNotes_FindInLinkedScope(context); return context; } try { List<NoteMetadata> notesMetadataList = BusinessNoteStore.FindNotesMetadata(context.noteFilter, context.maxResults, context.resultSpec); context.findMetadataResults.AddRange(notesMetadataList); // Remember which note guids came from the business. We'll use this later to // determine if we're worried about an inability to map back to notebooks. context.resultGuidsFromBusiness = notesMetadataList.Select((x) => x.Guid).Distinct(); //'Dim newList = notesMetadataList.[Select](Function(x) x.Guid).Distinct() context = FindNotes_FindInLinkedScope(context); } catch (Evernote.EDAM.Error.EDAMUserException ex) { if (ex.ErrorCode == Evernote.EDAM.Error.EDAMErrorCode.PERMISSION_DENIED) { // This is a business user, but apparently has an app notebook restriction that's // not in the business. Go look in linked scope. context = FindNotes_FindInLinkedScope(context); } else { ENSDKLogger.ENSDKLogError(string.Format("findNotes: Failed to find notes (business). {0}", ex.Message)); throw new Exception(ex.Message, ex.InnerException); } } catch (Exception ex) { ENSDKLogger.ENSDKLogError(string.Format("findNotes: Failed to find notes (business). {0}", ex.Message)); throw new Exception(ex.Message, ex.InnerException); } return context; }
private ENSessionFindNotesContext FindNotes_FindInPersonalScope(ENSessionFindNotesContext context) { bool skipPersonalScope = false; // Skip the personal scope if the scope notebook isn't personal, or if the scope // flag doesn't include personal. if (context.scopeNotebook != null) { //If the scope notebook isn't personal, skip personal. if (context.scopeNotebook.IsLinked) { skipPersonalScope = true; } } else if (!(context.scope.HasFlag(SearchScope.Personal))) { // If the caller didn't request personal scope. skipPersonalScope = true; } else if (AppNotebookIsLinked) { // If we know this is an app notebook scoped app, and we know the app notebook is not personal. skipPersonalScope = true; } // If we're skipping personal scope, proceed directly to business scope. if (skipPersonalScope) { context = FindNotes_FindInBusinessScope(context); return context; } try { List<NoteMetadata> notesMetadataList = PrimaryNoteStore.FindNotesMetadata(context.noteFilter, context.maxResults, context.resultSpec); context.findMetadataResults.AddRange(notesMetadataList); context = FindNotes_FindInBusinessScope(context); } catch (Exception ex) { ENSDKLogger.ENSDKLogError(string.Format("findNotes: Failed to find notes (personal). {0}", ex.Message)); throw new Exception(ex.Message, ex.InnerException); } return context; }
private ENSessionFindNotesContext FindNotes_ListNotebooks(ENSessionFindNotesContext context) { // XXX: We do the full listNotebooks operation here, which is overkill in all situations, // and could wind us up doing a bunch of extra work. Optimization is to only look at -listNotebooks // if we're personal scope, and -listLinkedNotebooks for linked and business, without ever // authenticating to other note stores. But it's also true that a findNotes may well be followed // quickly by a fetchNote(s), which is going to require the full notebook list anyway, and by then // it'll be cached. List<ENNotebook> notebooks = ListNotebooks(); if (notebooks != null) { context.allNotebooks = notebooks; context = FindNotes_FindInPersonalScope(context); } else { string err = "findNotes: Failed to list notebooks."; ENSDKLogger.ENSDKLogError(err); throw new Exception(err); } return context; }
public List<ENSessionFindNotesResult> FindNotes(ENNoteSearch noteSearch, ENNotebook notebook, SearchScope scope, SortOrder order, int maxResults) { if (!IsAuthenticated) { throw new ENAuthExpiredException(); } // App notebook scope is internally just an "all" search, because we don't a priori know where the app // notebook is. There's some room for a fast path in this flow if we have a saved linked record to a // linked app notebook, but that case is likely rare enough to prevent complexifying this code for. if (scope.HasFlag(SearchScope.AppNotebook)) { scope = SearchScope.All; } // Validate the scope and sort arguments. if (notebook != null && scope != SearchScope.None) { ENSDKLogger.ENSDKLogError("No search scope necessary if notebook provided."); scope = SearchScope.None; } else if (notebook == null && scope == SearchScope.None) { ENSDKLogger.ENSDKLogError("Search scope or notebook must be specified. Defaulting to personal scope."); scope = SearchScope.DefaultScope; } bool requiresLocalMerge = false; if (scope != SearchScope.None) { // Check for multiple scopes. Because linked scope can subsume multiple linked notebooks, that *always* triggers // the multiple scopes. If not, then both personal and business must be set together. if ((scope.HasFlag(SearchScope.Personal) && scope.HasFlag(SearchScope.Business)) || scope.HasFlag(SearchScope.PersonalLinked)) { // If we're asked for multiple scopes, relevance is not longer supportable (since we // don't know how to combine relevance on the client), so default to updated date, // which is probably the closest proxy to relevance. if (order.HasFlag(SortOrder.Relevance)) { ENSDKLogger.ENSDKLogError("Cannot sort by relevance across multiple search scopes. Using update date."); order = (EvernoteSDK.ENSession.SortOrder)EN_FLAG_CLEAR(order, SortOrder.Relevance); order = (EvernoteSDK.ENSession.SortOrder)EN_FLAG_SET(order, SortOrder.RecentlyUpdated); } requiresLocalMerge = true; } } NotesMetadataResultSpec resultSpec = new NotesMetadataResultSpec(); resultSpec.IncludeNotebookGuid = true; resultSpec.IncludeTitle = true; resultSpec.IncludeCreated = true; resultSpec.IncludeUpdated = true; resultSpec.IncludeUpdateSequenceNum = true; NoteFilter noteFilter = new NoteFilter(); noteFilter.Words = noteSearch.SearchString; if (order.HasFlag(SortOrder.Title)) { noteFilter.Order = (System.Int32)NoteSortOrder.TITLE; } else if (order.HasFlag(SortOrder.RecentlyCreated)) { noteFilter.Order = (System.Int32)NoteSortOrder.CREATED; } else if (order.HasFlag(SortOrder.RecentlyUpdated)) { noteFilter.Order = (System.Int32)NoteSortOrder.UPDATED; } else if (order.HasFlag(SortOrder.Relevance)) { noteFilter.Order = (System.Int32)NoteSortOrder.RELEVANCE; } // "Normal" sort is ascending for titles, and descending for dates and relevance. bool sortAscending = order.HasFlag(SortOrder.Title) ? true : false; if (order.HasFlag(SortOrder.Reverse)) { sortAscending = !sortAscending; } noteFilter.Ascending = sortAscending; if (notebook != null) { noteFilter.NotebookGuid = notebook.Guid; } // Set up context ENSessionFindNotesContext context = new ENSessionFindNotesContext(); context.scopeNotebook = notebook; context.scope = scope; context.order = order; context.noteFilter = noteFilter; context.resultSpec = resultSpec; context.maxResults = maxResults; context.findMetadataResults = new List<NoteMetadata>(); context.requiresLocalMerge = requiresLocalMerge; context.sortAscending = sortAscending; // If we have a scope notebook, we already know what notebook the results will appear in. // If we don't have a scope notebook, then we need to query for all the notebooks to determine // where to search. if (context.scopeNotebook == null) { context = FindNotes_ListNotebooks(context); return context.results; } context = FindNotes_FindInPersonalScope(context); return context.results; }