Skip to content

Extract acitivities into a separate plugin #6790

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
May 23, 2022
Merged

Conversation

smotornyuk
Copy link
Member

@smotornyuk smotornyuk commented Apr 3, 2022

Just as the title says. If anybody doesn't like the idea and the text below will not convince them, feel free to close this PR. Its only aim is to simplify activity improvements in the future and it has no value other than that.

Why?

  • Make core simpler
  • Activities naturally work as a separate extension. They don't change CKAN, they only add few new pages/actions. And there are no features inside activities that require low-level interactions with CKAN.
  • In this way people can extend/replace activities with their own implementation or with the newer version even when the CKAN core upgrade is not possible. For example, I would be really happy to have group changes feature from the CKAN master on my projects using CKAN v2.9. If activities are implemented as an extension, I can just download the activity extension from the upstream and register it as my-activity extension, getting all the new features. And it will be much simpler to locate any incompatibilities and bugs, because the extension is not as huge, as the CKAN core itself.
  • Narrow scope of changes, related to activities. For example, it will be much easier to locate and reuse code for Paginate activity list for datasets #6754
  • Put everything related to activities into one place. Usually, we improve only package activities, because no one knows all the places where activities are used. And afterward, someone asks to implement the same feature for the group activities(for example, group changes were not added to 2.9). And, do you remember that we have user activities, that are completely neglected by devs?:)
  • Identify issues that big extensions may have. It may serve us as a source of ideas on what can be improved. For example, while extracting activities, I noticed that we:
    • don't have a mechanism for registering models - even though action context has model property, it just contains ckan.model. There is no way to add\override items there. So it has sense either to extend this item or remove it from context(if it is there for simplifying the import, it's better to move it into the toolkit).
    • Don't have recommended way of defining new models and attaching them to the sqlalchemy's metadata. I've created ckan.model.base:Base instance of SQLAlchemy's declarative base, which can be a solution for this problem.
    • Don't have a recommended way for setting relationships between plugins. For example, stats plugins depend on activities. If the activity plugin is disabled, old stats can be shown, but there will be no updates to them.

Details

ℹ️ I only moved the code and tried to keep all the features\details\bugs in place. All the improvements and refactoring can be done separately("Good for contribution").

I created the activity plugin and moved almost everything related to activities into it:

  • activity API
  • activity model
  • activity templates
  • extracted changes/history/activity endpoints from package/group/user blueprints and moved them into the activity view
  • a couple of helpers
  • few validators
  • dashboard.index page
  • activity tests

What I left:

  • following functionality
  • config declarations
  • "Subscribe to activity notifications" flag from the user's profile

If you have activity enabled, everything should work as it was before, but there are a couple of changes in code required:

  • import ckan.model.Activity -> import ckanext.activity.model.Activity
  • url_for("dataset/group/user.activity/changes/changes_multiple") -> url_for("activity.package/group/user_activity/changes/changes_multiple")

If the activity plugin is not enabled:

  • new activities are not created
  • corresponding API actions are not available
  • Activity pages from the user's profile, dataset, and group\organization pages are not shown
  • Dashboard has no activity tab. After login user is redirected to dashboard.datasets instead.

If you are wondering, how activities are created, there is no magic. I've just used signals:)

PS sorry for another big PR

@smotornyuk smotornyuk force-pushed the activity-extension branch from de37100 to 09ece3f Compare April 3, 2022 03:18
@amercader amercader added this to the CKAN 2.10 milestone Apr 7, 2022
@tino097 tino097 mentioned this pull request Apr 25, 2022
5 tasks
Copy link
Member

@amercader amercader left a comment

Choose a reason for hiding this comment

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

Had a first quick look and overall it looks good, see some questions and comments @smotornyuk

My main concerns are compatibility, making the transition transparent for most users, specially regarding URLs.

For those wanting to have a look check the changes in the logic folder, specially where the new action_succeededsignal is fired, and the subscriptions file where the activity plugin registers its listeners

'activity_type': 'new user',
}
logic.get_action('activity_create')(activity_create_context, activity_dict)
# session.flush()
Copy link
Member

Choose a reason for hiding this comment

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

Let's remove this and the comment above is no longer required

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, has sense.

@@ -0,0 +1,5 @@
Activites extracted into `activity` plugin:
Copy link
Member

Choose a reason for hiding this comment

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

We should make clear that users should add the activity plugin to their ckan.plugins config option if they want to keep seeing the activities!

Copy link
Member

Choose a reason for hiding this comment

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

Also I think this plugin should be added by default when creating a new ini file (can we add a default for ckan.plugins like we use to do adding stuff to deployment.ini_tmpl?

Copy link
Member

Choose a reason for hiding this comment

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

i agree about adding as default to ckan.plugins

Copy link
Member Author

@smotornyuk smotornyuk May 15, 2022

Choose a reason for hiding this comment

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

Yep, changelog record updated and activity added to the list of plugins inside the generated config file

@@ -159,12 +64,6 @@ def groups() -> str:
return base.render(u'user/dashboard_groups.html', extra_vars)


dashboard.add_url_rule(
Copy link
Member

Choose a reason for hiding this comment

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

Will url_for('dashboard.index') still work? Otherwise is a pain in the ass for extensions

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it works but produces the following log record:

2022-05-15 18:40:30,579 INFO  [ckan.lib.helpers] Route name "dashboard.index" is deprecated and will be removed. Please update calls to use "activity.dashboard" instead

Comment on lines +103 to +105
activity = Activity.activity_stream_item(pkg, type_, user_id)
context["session"].add(activity)
context["session"].commit()
Copy link
Member

Choose a reason for hiding this comment

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

Why aren't the dataset activities created via the activity_create action like the group or user ones?

Copy link
Member Author

Choose a reason for hiding this comment

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

activity_create action requires an existing user ID. Such code bypasses this restriction. If you check a few lines above, you'll see user_id = 'not logged in' line, which allows changing a package anonymously(via ignore_auth I suppose).

Even though it looks like a really bad idea, we cannot just require an existing user here. I definitely have seen not logged in in the activity streams, which means that such a change can potentially break existing workflows.

So it's one of those "bugs and problems" that I noticed and decided to keep in order to avoid behavioral changes as much as possible.

@@ -452,50 +450,12 @@ def read(package_type: str, id: str) -> Union[Response, str]:

g.pkg_dict = pkg_dict
g.pkg = pkg
# NB templates should not use g.pkg, because it takes no account of
Copy link
Member

Choose a reason for hiding this comment

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

IIUC We are changing the URL here right? so on CKAN < 2.10 it would be:

/dataset/my-dataset?activity_id=<activity_id>

And going forward it will be:

/dataset/my-dataset/archive/<activity_id>

Can we keep a small compatibility check to not break URLs? Something like:

if p.plugin_loaded("activity"):
    activity_id = request.args.get("activity_id")
    if activity_id:
        return redirect("activity.package_archive", id=pkg_id, activity_id=activity_id)

WDYT?

(also see note about the name "archive" below)

Copy link
Member Author

Choose a reason for hiding this comment

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

makes perfect sense. I wanted to handle this case, but I just hadn't come to such an obvious solution 😆

return tk.render("package/resource_archive.html", extra_vars)


@bp.route('/dataset/<id>/archive/<activity_id>')
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure about "archive" to describe this. Maybe "history"?

@ckan/core any thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

as the method names are _archive maybe we should keep with that but also the option of _activities could have more sense as we use that in tests for the creation of the activities

})

try:
package = tk.get_action(u'package_show')(context, {u'id': id})
Copy link
Member

Choose a reason for hiding this comment

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

Can we get rid of all the u prefixes on all new files? 🙏
(and maybe blackify them :p, or at least use double quotes consistently. but only the new ones!)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I like this idea. I'll keep the current formatting till activity-pagination PR is merged so that there will be fewer conflicts. And then I'll run all activity-plugin files through black

@amercader
Copy link
Member

This is good to go!

@smotornyuk #6798 is also good to be merged. If I understood correctly in here we should merge #6798 first, then you pick the changes in this PR right?

@smotornyuk
Copy link
Member Author

Updated. I think that all mentioned issues were addressed, so it's ready for the second round of review.

@amercader
Copy link
Member

@smotornyuk all good. Do you want to first merge this and then port the #6798 changes on a separate PR or add them here and then merge?

@smotornyuk
Copy link
Member Author

smotornyuk commented May 22, 2022

I've already ported it. The last four commits(starting from 83c2755) contain the upstream with #6798 included 😄

@amercader amercader merged commit f079328 into master May 23, 2022
@amercader amercader deleted the activity-extension branch May 23, 2022 10:15
@amercader
Copy link
Member

Thanks @smotornyuk !

Next up, port the pagination changes to the user, group etc activity streams

@smotornyuk
Copy link
Member Author

Thank you for the quick review:)

@avdata99, this PR is merged, so you can use it for replicating your pagination-feature. I've tried to keep every bit of functionality from activity-streams intact and basically just moved the code and templates to the ckanext/activity folder. But if you have some questions or issues, don't hesitate and mention me somewhere in the comment to your PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants