https://github.com/tfwright/spur
Activity tracking for Ecto
https://github.com/tfwright/spur
activity-feed ecto elixir hacktoberfest phoenix-framework
Last synced: 3 months ago
JSON representation
Activity tracking for Ecto
- Host: GitHub
- URL: https://github.com/tfwright/spur
- Owner: tfwright
- Created: 2019-04-09T22:34:33.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2021-05-26T15:10:04.000Z (over 4 years ago)
- Last Synced: 2024-05-02T00:22:44.544Z (over 1 year ago)
- Topics: activity-feed, ecto, elixir, hacktoberfest, phoenix-framework
- Language: Elixir
- Homepage: https://hex.pm/packages/spur
- Size: 60.5 KB
- Stars: 27
- Watchers: 3
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
Awesome Lists containing this project
README
# Spur
[](https://hex.pm/packages/spur)
[](https://github.com/tfwright/spur/actions)
Loosely based on [chaps-io/public_activity](http://github.com/chaps-io/public_activity), a very simple utility for quickly setting up an activity stream in your Elixir/Ecto app.
More detailed examples of configuration and usage are in the [tests](https://github.com/tfwright/spur/blob/master/test/spur_test.exs). See [this thread](https://elixirforum.com/t/spur-very-simple-activity-streams-for-ecto/22086?u=tfwright) for more information on the idea behind Spur and the changelog.
## Installation
Basic steps are
1. Add Spur to your application `deps`.
2. Tell Spur which Ecto Repo to use:
```
config :spur, repo: MyApp.Repo
```
3. Generate and run a migration that adds an "activities" table to your repo (see priv/test/migrations). To use a different table name, set the `activities_table_name` config.
That's enough to start tracking arbitrary activities:
```
%Spur.Activity{actor: "caesar", action: "came", object: "your-county", meta: %{also: ["saw", "conquered"]}}
```
Fields are based on https://www.w3.org/TR/activitystreams-core/#example-1
## Getting fancy
### "Callbacks"
If you want to make use of automatic tracking of inserts, updates and deletes, make sure your objects implement the required fields as functions:
```
defmodule Battle do
defimpl Spur.Trackable, for: __MODULE__ do
def actor(war), do: "Accounts.User:#{war.general_id}"
def object(war), do: "war:#{war.id}"
def target(_war), do: nil
end
end
```
Now instead of using `Repo` to perform your operation, use `Spur` instead:
```
%MyApp.Battle{general_id: 5}
|> MyApp.Battle.changeset
|> Spur.insert
```
In this example, a record for both your `Battle` and an `Activity` with action set to insert will be stored in the DB. Of course, the `Battle` fails validations, neither will be inserted and the changeset will be returned with errors, just as `Repo` would. Otherwise it will return the `Battle`. (*Note*: As of 0.3.0, Spur supports the `expose_transactions` config, which when sets to true returns the raw Ecto transaction. Us this if you need to access the created `Activity` struct.)
Each of these callback functions also take a `Map` of properties that will be added to the `Activity` record, or a `Function` that returns a `Map`. You can use this to set or override default Activity data in the callback itself. If, for example, the actor for a given schema is not stored in the Repo, you may want to use the logged in user instead:
```
Spur.insert(changeset, %{actor: conn.assigns.current_user.id})
```
### Audience
To automatically associate the `Activity` with an [audience](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audience) requires a bit of extra configuration:
1. Add `audience_module` to your app's Spur config: `audience_module: MyApp.Accounts.User`
2. Add a `many_to_many` association between your audience module's Ecto schema. By default Spur expects this to be named `:activities`. If you want to name it something else, add another line to the config: `audience_assoc_name: :events`.
3. Finally, make sure that your trackable objects implement `audience`. It should return either an Ecto query or a plain list of the audience structs configured with the above association.
Now when you use one of the callback's above to track an object, the resulting `Activity` will automatically be associated with the audience records returned for that object:
# SpurTest.TrackableStruct
def audience(trackable_struct), do: Ecto.assoc(trackable_struct, :watchers)
[watcher] = trackable_struct.watchers
Ecto.Changeset.change(trackable_struct)
|> Spur.update
[%Spur.Activity{action: update}] = watcher.activities
---
> <>
>
> Hans Georg-Gadamer, "Hermeneutik auf dem Spur"