Is there any way to change the timestamp date and time when a topic was created?


(Tobias Eigen) #1

I have embedded discourse in my blog, and it has been automagically generating topics for each post in the blog as the blog pages get accessed. This is great, but it looks like new content when in fact it’s an archive of posts and should not be so prominent in the forums. I don’t see any way to change this, even as an admin.


Embedding Discourse on Ghost Blog
(Jeff Atwood) #2

Probably you would need to do this via the Ruby console and direct model updates at the command line. @riking can probably tell you how, I bet! :wink:


(Kane York) #3

Yes, but a UI would be nice.

This might not be right, but here:

$ ./launcher ssh app

$ rails c
> p = Post.where(topic_id: 15393, post_number: 2)
<Post id: 51956, ..... >
# -- OR --
> p = Post.find(51956)

> d = DateTime.parse("7 may 2014 05:03")
> p.posted_at = d # or something, maybe created_at

Where 51956 is $E.get('postStream').stream[POST_NUMBER - 1] in the JS console, after assigning the Topic to $E.


(Lars Doucet) #4

I’m not quite sure I understand, you’re being a bit terse here :slight_smile: Can you de-jargonify for less savvy folks like me?

I know how to open the ruby console and how to open the JS console. I’ve opened the JS console on the post in question and I assume I need to run a command to get the post id, which I’ll plug into the ruby command.

Where 51956 is $E.get(‘postStream’).stream[POST_NUMBER - 1] in the JS console, after assigning the Topic to $E.

So if my topic in the url bar is “this-is-a-topic”, then do this in Google Chrome JS console?

> $E = "this-is-a-topic"

And then run:

> $E.get('postStream').stream[POST_NUMBER - 1]

At which point I get some number?

And then run the above ruby code?

That’s the assumption I’m going with. This is what I get:

$E = 'this-is-a-topic'
"this-is-a-topic"

$E.get('postStream').stream[POST_NUMBER - 1]
TypeError: undefined is not a function

so clearly I’m not doing this right.


(Lars Doucet) #5

Okay, figured it out. I was overthinking it. You can see the topic in the url, no need for JS.

 p = Post.find(51956)

> d = DateTime.parse("7 may 2014 05:03")
> p.created_at

Looks like it’s created_at, not posted_at. There’s also updated_at and bumped_at, and those variables exist not only for the topic but also for individual posts.

However, after I run these functions, nothing seems to change. The same dates remain on the main page after I run them. So I start/stop the app with docker, and now the ruby console shows me the date values have reverted.

How do I change the values and get them to stick?

UPDATE:
Okay, I’m underthinking it. I can find the topic number from the top, but not the post id. I’ve been trying to re-order posts that were imported via EvilTrout’s embedding discourse-on-a-blog-feature. I want the timestamps to match the post dates for the original blog posts, not the day I hooked up the embed scripts.


(Kane York) #6

Yup. I guess I overcomplicated it - I provided a way to get the post ID if you have Ember Debugger installed. However, you don’t need it - you can query by topic ID and post number.

The topic ID is what’s at the top, and the post number you can get from the permalinks.

The p = Post.where(topic_id: 15393, post_number: 2) will be sufficient.


(Lars Doucet) #7

Great! Thanks very much. Any insights as to whether I’m doing something wrong with setting the values as they don’t seem to stay that way, nor do they reflect any changes to user-facing post/create dates?


(Kane York) #8

You’ll need to run p.save if you make any changes that aren’t auto-committed.


(Lars Doucet) #9

great! Thanks :slight_smile: I’m new to this.


(Lars Doucet) #10

Interesting. I can set:

updated_at
created_at
bumped_at

For a topic that I grab with Topic.find(NUMBER), but it doesn’t work for a post I grab with Post.where(topic_id:NUMBER, post_number:NUMBER).

Some spew:

irb(main):045:0> t = Topic.find(346)
=> #<Topic id: 346, title: "Indie Solidarity - Telepath Tactics", last_posted_at: nil, created_at: "2014-05-23 23:24:26", updated_at: "2014-05-23 23:24:26", views: 17, posts_count: 1, user_id: 1, last_post_user_id: 1, reply_count: 0, featured_user1_id: nil, featured_user2_id: nil, featured_user3_id: nil, avg_time: nil, deleted_at: nil, highest_post_number: 1, image_url: "/uploads/default/43/16c051970627351b.png", off_topic_count: 0, like_count: 0, incoming_link_count: 0, bookmark_count: 0, star_count: 0, category_id: 7, visible: true, moderator_posts_count: 0, closed: false, archived: false, bumped_at: "2014-05-23 23:24:26", has_summary: false, vote_count: 0, archetype: "regular", featured_user4_id: nil, notify_moderators_count: 0, spam_count: 0, illegal_count: 0, inappropriate_count: 0, pinned_at: nil, score: 0.0, percent_rank: 0.813813813813814, notify_user_count: 0, subtype: nil, slug: "indie-solidarity-telepath-tactics", auto_close_at: nil, auto_close_user_id: nil, auto_close_started_at: nil, deleted_by_id: nil, participant_count: 1, word_count: 1843, excerpt: "Today a bit of a personal post.  We have been pret...", pinned_globally: false>
irb(main):046:0> 

Then doing the same for p:

p = Post.where(topic_id: 346, post_number: 1)
=> #<ActiveRecord::Relation [#<Post id: 2352, user_id: 1, topic_id: 346, post_number: 1, raw: "<p>Today a bit of a personal post.<br><br>We have ...", cooked: "<p>Today a bit of a personal post.<br><br>We have ...", created_at: "2014-05-23 23:24:26", updated_at: "2014-05-26 18:16:14", reply_to_post_number: nil, reply_count: 0, quote_count: 0, deleted_at: nil, off_topic_count: 0, like_count: 0, incoming_link_count: 0, bookmark_count: 0, avg_time: nil, score: 0.0, reads: 1, post_type: 1, vote_count: 0, sort_order: 1, last_editor_id: -1, hidden: false, hidden_reason_id: nil, notify_moderators_count: 0, spam_count: 0, illegal_count: 0, inappropriate_count: 0, last_version_at: "2014-05-23 23:30:32", user_deleted: false, reply_to_user_id: nil, percent_rank: 0.0, notify_user_count: 0, like_score: 0, deleted_by_id: nil, edit_reason: "downloaded local copies of images", word_count: 1843, version: 4, cook_method: 2, wiki: false>]>

I create a date-time like you mentioned, inspects as:

irb(main):047:0> d
=> Fri, 21 Dec 2012 11:09:00 +0000

Then I set some variables for t:

irb(main):049:0> t.created_at = t.updated_at = t.bumped_at = d
=> Fri, 21 Dec 2012 11:09:00 +0000

And for p, causing errors:

irb(main):054:0> p.created_at = p.updated_at = d
NoMethodError: undefined method `updated_at=' for #<Post::ActiveRecord_Relation:0x007ff6b7d56460>
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation/delegation.rb:136:in `method_missing'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation/delegation.rb:99:in `method_missing'
        from (irb):57
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/console.rb:90:in `start'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/console.rb:9:in `start'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/commands_tasks.rb:69:in `console'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands.rb:17:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'

This happens whether or not I set both variables for p at once or just one or the other.

I then save t & p:

irb(main):055:0> t.save
=> false
irb(main):056:0> p.save
NoMethodError: undefined method `save' for #<Post::ActiveRecord_Relation:0x007ff6b7d56460>
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation/delegation.rb:136:in `method_missing'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation/delegation.rb:99:in `method_missing'
        from (irb):56
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/console.rb:90:in `start'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/console.rb:9:in `start'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/commands_tasks.rb:69:in `console'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands.rb:17:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'

And that’s the result. Refreshing and inspecting the original post, it still says it was created 3 days ago (the day I imported it from my blog), rather than the date I’m trying to manually set it to.

It’s weird that p.updated_at and p.created_at throw errors when the values are clearly there, right? And why does it return false when I try to save? Anyways, I’m totally confused.

Would really like to just be able to set this property in an admin panel or something :slight_smile:


UPDATE: Changing timestamp through UI
(Jens Maier) #11

Your p is not a single Post object but a collection of posts because the query where(topic_id: 346, post_number: 1) could in theory return more then one post. Try this:

p = Post.where(topic_id: 346, post_number: 1).first

By the way, Ruby told you about this: t was a #<Topic ...> while p was a #<ActiveRecord::Relation [#<Post ...>]>:smile:


(Lars Doucet) #12

I’m super new to ruby, thanks for the clarification. Let’s see if this works!

UPDATE:

It works! It won’t let me save the topic (returns false), but it will let me save the post (returns true). I refreshed, and it affects the visible posting date on the site itself.

Now let’s see if I can use this to manually resort all my imported blog posts.

2nd UPDATE:
Seems like this method will update the first post in a topic, but I’d still like to “bury” the topic itself (not sure why I get returns false on modify t variable). I have several dozen imported blog posts, some several years old, that are cluttering up my front page.


(Jens Maier) #14

That’s weird, I can’t reproduce that symptom. Try just modifying the topic’s timestamps and store with t.save!; this should cause ActiveRecord to complain loudly about any problems (probably a failing validation?) rather then just return a nondescript false…


(Lars Doucet) #15

Okay, thanks! Here’s the spew:

irb(main):009:0> t.save!
ActiveRecord::RecordInvalid: Validation failed: Title has already been used
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:57:in `save!'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/attribute_methods/dirty.rb:29:in `save!'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:273:in `block in save!'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `block in transaction'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:219:in `within_new_transaction'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:208:in `transaction'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:273:in `save!'
        from (irb):9
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/console.rb:90:in `start'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/console.rb:9:in `start'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/commands_tasks.rb:69:in `console'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
        from /var/www/discourse/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands.rb:17:in `<top (required)>'
        from script/rails:6:in `require'

Perhaps this is a side-effect of an imported post? Maybe it let some data get snuck into the database on the sly without being properly hammered into shape by Discourse?


(Jens Maier) #16

Looks like it. The importer created two (or more) topics with the same title which Discourse normally forbids.

You should probably fix this issue or risk running into other problems down the line, but for now you can update the topic’s timestamps with:

t.save(validate: false)

(Lars Doucet) #17

Okay, so, can I fix the duplicate titled posts in the regular admin interface, or will it take further database trickery? (Ie, does deleting/changing the duplicate-titled post actually change the underlying variable, or just the user-facing title text?)

UPDATE:
This is working great, by the way.

UPDATE 2:
Found a bunch of duplicate posts, from my imported blogs. Deleted/merged, I should be all cleaned up now?


(Jens Maier) #18

Hopefully, but I guess you can’t be completely certain. The converter has probably also shoehorned short or repetitive posts into Discourse using the validation: false flag, so future changes involving these posts may face similar problems.

Actually, I’m curious… see if you can find a really short post, like 5 characters or under, and try to delete it.

For science! :wink:


(Phillip Schichtel) #19

As I found this thread via google I’d like to post the code I successfully used to update my topics’ dates:

def u(id, date)
    t = Topic.where(id: id).first
    p = Post.where(topic_id: id, post_number: 1).first

    time = DateTime.parse("#{date} +0100")

    t.created_at = time
    t.updated_at = time
    t.last_posted_at = time
    t.bumped_at = time
    t_saved = t.save

    p.created_at = time
    p.updated_at = time
    p.last_version_at = time
    p.baked_at = time
    p_saved = p.save
    
    return t_saved && p_saved
end

It updates all *_at fields except the deleted_at field to the given time (with the +0100 timezone, should be changed)


(Mick Hellstrom) #20

I had the same issue as well and came across this post. Thanks @pschichtel for this, (since I’m a Ruby nooby as well).

I’ve extended it so that it’ll search for the URL reference of the WP post.

def u(url, date)
 t = Topic.where(featured_link: url).first
 puts t.title
 p = Post.where(topic_id: t.id, post_number: 1).first
 puts p.created_at

 time = DateTime.parse("#{date} -1000")

 t.created_at = time
 t.updated_at = time
 t.last_posted_at = time
 t.bumped_at = time
 t_saved = t.save

 p.created_at = time
 p.updated_at = time
 p.last_version_at = time
 p.baked_at = time
 p_saved = p.save
 puts p.created_at

 return t_saved && p_saved
end

Then you can update all your Discourse topics in one hit by copying and pasting the output from this on your WP box.

wp post list --skip-plugins --fields=ID,post_status,url,post_date | sort -rnk1 | awk -F\\t '$2~/publish/{print"u(\""$3"\", \""$4"\")"}'

It’d be good to have the ability to match the Discourse topic date with the WP post date automatically.


(Joshua Rosenfeld) #21

Changing the timestamp can now be done via the UI. As admin click the wrench on the topic and click “Change Timestamp”.