Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions WordPress/Classes/Models/AbstractPost+HashHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@ NS_ASSUME_NONNULL_BEGIN
// This value is used in Offline Posting — to calculate whether the post that the user _wanted_ to publish,
// hasn't changed in the meantime and still is the same post.
// It works by calculating a SHA256 hash for a subset of properties of a Post and then combining them together (including the hashes returned by the `additionalContentHashes` method, to let subclasses provide additional sources of truthfulness).
/// - note: deprecated (kahu-offline-mode)
- (NSString *)calculateConfirmedChangesContentHash;

// This is an extension point for the subclasses to add additional sources of truthfulness.
/// - note: deprecated (kahu-offline-mode)
- (NSArray<NSData *> *)additionalContentHashes;


/// - note: deprecated (kahu-offline-mode)
- (NSData *)hashForString:(NSString *)string;
/// - note: deprecated (kahu-offline-mode)
- (NSData *)hashForNSInteger:(NSInteger)integer;
/// - note: deprecated (kahu-offline-mode)
- (NSData *)hashForDouble:(double)dbl;

@end
Expand Down
2 changes: 2 additions & 0 deletions WordPress/Classes/Models/AbstractPost+Local.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import Foundation

extension AbstractPost {
/// Returns true if the post is a draft and has never been uploaded to the server.
/// - note: deprecated (kahu-offline-mode)
var isLocalDraft: Bool {
return self.isDraft() && !self.hasRemote()
}

/// - warning: deprecated (kahu-offline-mode)
var isLocalRevision: Bool {
return self.originalIsDraft() && self.isRevision() && self.remoteStatus == .local
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
/// eventually be made private.
/// - SeeAlso: PostCoordinator.resume
///
/// - note: deprecated (kahu-offline-mode)
func markAsFailedAndDraftIfNeeded() {
guard self.remoteStatus != .failed else {
return
Expand Down
14 changes: 12 additions & 2 deletions WordPress/Classes/Models/AbstractPost.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,19 @@ typedef NS_ENUM(NSUInteger, AbstractPostRemoteStatus) {
@property (nonatomic, copy, nullable) NSDate *autosaveModifiedDate;
@property (nonatomic, copy, nullable) NSNumber *autosaveIdentifier;

@property (nonatomic, strong, nullable) NSString *confirmedChangesHash;
@property (nonatomic, strong, nullable) NSDate *confirmedChangesTimestamp;

// Revision management
- (AbstractPost *)createRevision;
/// A new version of `createRevision` that allows you to create revisions based
/// on other revisions.
///
/// - warning: Work-in-progress (kahu-offline-mode)
- (AbstractPost *)_createRevision;
- (void)deleteRevision;
- (void)applyRevision;
- (AbstractPost *)updatePostFrom:(AbstractPost *)revision;
- (void)updateRevision;
- (BOOL)isRevision;
- (BOOL)isOriginal;

Expand All @@ -73,7 +80,7 @@ typedef NS_ENUM(NSUInteger, AbstractPostRemoteStatus) {
- (BOOL)hasCategories;
- (BOOL)hasTags;

/// True if either the post failed to upload, or the post has media that failed to upload.
/// - note: deprecated (kahu-offline-mode)
@property (nonatomic, assign, readonly) BOOL isFailed;

@property (nonatomic, assign, readonly) BOOL hasFailedMedia;
Expand All @@ -86,7 +93,9 @@ typedef NS_ENUM(NSUInteger, AbstractPostRemoteStatus) {
- (BOOL)hasRevision;

#pragma mark - Conveniece Methods
/// - note: deprecated (kahu-offline-mode)
- (void)publishImmediately;
/// - note: deprecated (kahu-offline-mode)
- (BOOL)shouldPublishImmediately;
- (NSString *)authorNameForDisplay;
- (NSString *)blavatarForDisplay;
Expand Down Expand Up @@ -176,6 +185,7 @@ typedef NS_ENUM(NSUInteger, AbstractPostRemoteStatus) {
*
* @returns YES if there ever was an attempt to upload this post, NO otherwise.
*/
/// - warning: deprecated (kahu-offline-mode)
- (BOOL)hasNeverAttemptedToUpload;

/**
Expand Down
35 changes: 6 additions & 29 deletions WordPress/Classes/Models/AbstractPost.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,6 @@
#import "BasePost.h"
@import WordPressKit;

@interface AbstractPost ()

/**
The following pair of properties is used to confirm that the post we'll be trying to automatically retry uploading,
hasn't changed since user has tapped on "confirm", and that we're not suddenly trying to auto-upload a post that the user
might have already forgotten about.

The public-facing counterparts of those is the `shouldAttemptAutoUpload` property.
*/

@property (nonatomic, strong, nullable) NSString *confirmedChangesHash;
@property (nonatomic, strong, nullable) NSDate *confirmedChangesTimestamp;

@end

@implementation AbstractPost

@dynamic blog;
Expand Down Expand Up @@ -151,8 +136,13 @@ - (AbstractPost *)createRevision
return self.revision;
}

return [self _createRevision];
}

- (AbstractPost *)_createRevision {
AbstractPost *post = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self.class) inManagedObjectContext:self.managedObjectContext];
[post cloneFrom:self];
post.isSyncNeeded = NO;
[post setValue:self forKey:@"original"];
[post setValue:nil forKey:@"revision"];
post.isFeaturedImageChanged = self.isFeaturedImageChanged;
Expand Down Expand Up @@ -193,14 +183,6 @@ - (AbstractPost *)updatePostFrom:(AbstractPost *)revision
return self;
}

- (void)updateRevision
{
if ([self isRevision]) {
[self cloneFrom:self.original];
self.isFeaturedImageChanged = self.original.isFeaturedImageChanged;
}
}

- (BOOL)isRevision
{
return (![self isOriginal]);
Expand All @@ -213,11 +195,6 @@ - (BOOL)isOriginal

- (AbstractPost *)latest
{
// Even though we currently only support 1 revision per-post, we have plans to support multiple
// revisions in the future. That's the reason why we call `[[self revision] latest]` below.
//
// - Diego Rey Mendez, May 19, 2016
//
return [self hasRevision] ? [[self revision] latest] : self;
}

Expand All @@ -239,7 +216,6 @@ - (AbstractPost *)original
return original;
}


#pragma mark - Helpers

- (BOOL)dateCreatedIsNilOrEqualToDateModified
Expand Down Expand Up @@ -496,6 +472,7 @@ - (BOOL)isUploading

#pragma mark - Post

/// - note: Deprecated (kahu-offline-mode)
- (BOOL)canSave
{
NSString* titleWithoutSpaces = [self.postTitle stringByReplacingOccurrencesOfString:@" " withString:@""];
Expand Down
69 changes: 69 additions & 0 deletions WordPress/Classes/Models/AbstractPost.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@ extension AbstractPost {
original?.original() ?? self
}

/// Returns `true` if the post was never uploaded to the remote and has
/// not revisions that were marked for syncing.
var isNewDraft: Bool {
assert(isOriginal(), "Must be called on the original")
return !hasRemote() && getLatestRevisionNeedingSync() == nil
}

// MARK: - Status

/// - note: deprecated (kahu-offline-mode)
@objc
var statusTitle: String? {
guard let status = self.status else {
Expand All @@ -17,6 +25,7 @@ extension AbstractPost {
return AbstractPost.title(for: status)
}

/// - note: deprecated (kahu-offline-mode)
@objc
var remoteStatus: AbstractPostRemoteStatus {
get {
Expand Down Expand Up @@ -150,4 +159,64 @@ extension AbstractPost {
func hasPermanentFailedMedia() -> Bool {
return media.first(where: { !$0.willAttemptToUploadLater() }) != nil
}

/// Returns the changes made in the current revision compared to the
/// previous revision or the original post if there is only one revision.
var changes: RemotePostUpdateParameters {
guard let original else {
return RemotePostUpdateParameters() // Empty
}
return RemotePostUpdateParameters.changes(from: original, to: self)
}

/// Returns all revisions of the post including the original one.
var allRevisions: [AbstractPost] {
var revisions: [AbstractPost] = [self]
var current = self
while let next = current.revision {
revisions.append(next)
current = next
}
return revisions

}

// TODO: Replace with a new flag
/// - note: Work-in-progress (kahu-offline-mode)
@objc var isSyncNeeded: Bool {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm planning to add a new flag to the database but only after we merge the changes in trunk and after 24.6 is cut. We'll be also removing some data.

get { confirmedChangesHash == AbstractPost.syncNeededKey }
set { confirmedChangesHash = newValue ? AbstractPost.syncNeededKey : "" }
}

static let syncNeededKey = "sync-needed"

/// Returns the latest saved revisions that needs to be synced with the server.
/// Returns `nil` if there are no such revisions.
func getLatestRevisionNeedingSync() -> AbstractPost? {
assert(original == nil, "Must be called on an original revision")
let revision = allRevisions.last(where: \.isSyncNeeded)
guard revision != self else {
return nil
}
return revision
}

/// Deletes all of the synced revisions until and including the `latest`
/// one passed as a parameter.
func deleteSyncedRevisions(until latest: AbstractPost) {
assert(original == nil, "Must be called on an original revision")
let tail = latest.revision

var current = self
while current !== latest, let next = current.revision {
current.deleteRevision()
current = next
}

if let tail {
willChangeValue(forKey: "revision")
setPrimitiveValue(tail, forKey: "revision")
didChangeValue(forKey: "revision")
}
}
}
66 changes: 33 additions & 33 deletions WordPress/Classes/Models/Post.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,41 +55,12 @@ class Post: AbstractPost {
}
}

// MARK: - Properties

fileprivate var storedContentPreviewForDisplay = ""

// MARK: - NSManagedObject

override class func entityName() -> String {
return "Post"
}

override func awakeFromFetch() {
super.awakeFromFetch()
buildContentPreview()
}

override func willSave() {
super.willSave()

if isDeleted {
return
}

storedContentPreviewForDisplay = ""
}

// MARK: - Content Preview

fileprivate func buildContentPreview() {
if let excerpt = mt_excerpt, excerpt.count > 0 {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was buggy and not effective as it would constantly reset.

storedContentPreviewForDisplay = excerpt.makePlainText()
} else if let content = content {
storedContentPreviewForDisplay = content.summarized()
}
}

// MARK: - Format

@objc func postFormatText() -> String? {
Expand Down Expand Up @@ -301,11 +272,23 @@ class Post: AbstractPost {
// MARK: - BasePost

override func contentPreviewForDisplay() -> String {
if storedContentPreviewForDisplay.count == 0 {
buildContentPreview()
if let excerpt = mt_excerpt, excerpt.count > 0 {
if let preview = PostPreviewCache.shared.excerpt[excerpt] {
return preview
}
let preview = excerpt.makePlainText()
PostPreviewCache.shared.excerpt[excerpt] = preview
return preview
} else if let content = content {
if let preview = PostPreviewCache.shared.content[content] {
return preview
}
let preview = content.summarized()
PostPreviewCache.shared.content[content] = preview
return preview
} else {
return ""
}

return storedContentPreviewForDisplay
}

override func hasLocalChanges() -> Bool {
Expand Down Expand Up @@ -387,3 +370,20 @@ class Post: AbstractPost {
hash(for: isStickyPost ? 1 : 0)]
}
}

private final class PostPreviewCache {
static let shared = PostPreviewCache()

let excerpt = Cache<String, String>()
let content = Cache<String, String>()
}

private final class Cache<Key: Hashable, Value> {
private let lock = NSLock()
private var dictionary: [Key: Value] = [:]

subscript(key: Key) -> Value? {
get { lock.withLock { dictionary[key] } }
set { lock.withLock { dictionary[key] = newValue } }
}
}
Loading