Skip to content

Commit 1e686c6

Browse files
committed
Add PutPreferences() support.
Add documentation for user preferences Exclude the identitymodel dpop fork from docs. Remove references to session in exception documentation.
1 parent 67b1c89 commit 1e686c6

28 files changed

+305
-39
lines changed

docs/docs/commonTerms.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
---
2-
uid: commonTerms
3-
---
4-
51
# Concepts & Common Terms
62

73
Before we go any further lets take a little time to explain some common terms that you will see when discussing AT Protocol and Bluesky APIs.

docs/docs/connecting.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,12 @@ OAuthClient and then send the user to the URI. The user will log into Bluesky an
9999
OAuthClient oAuthClient = agent.CreateOAuthClient();
100100
Uri startUri = await agent.BuildOAuth2LoginUri(oAuthClient, handle, cancellationToken: cancellationToken);
101101

102-
// Save the state, and persist it in whatever way is suitable for your application, to be used when the response comes back from the OAuth server.
102+
// Save the state, and persist it in whatever way is suitable for your application,
103+
// to be used when the response comes back from the OAuth server.
103104
OAuthLoginState oAuthLoginState = uriBuilderOAuthClient.State;
104105

105-
// Send the user to the startUri in a way suitable for your application, a redirection for web application or spawning a browser for a desktop application.
106+
// Send the user to the startUri in a way suitable for your application,
107+
// a redirection for web application or spawning a browser for a desktop application.
106108
```
107109

108110
When the user returns to your application you take the callback data returned from the OAuth server and process it

docs/docs/conversationsAndMessages.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
> [!IMPORTANT]
66
> If you or your users are using app passwords they must select the option to "Allow access to your direct messages" when creating the app password for
77
> any of the conversation apis to work.
8+
>
9+
> If you are using [OAuth](connecting.md#oauth) you must request the `transition:chat.bsky` scope.
810
911
To get a list of conversations for the authenticated user use the `ListConversations()` api:
1012

docs/docs/endpointStatus.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
| | [app.bsky.actor.getProfiles](https://docs.bsky.app/docs/api/app-bsky-actor-get-profiles) | `BlueskyAgent.GetProfiles()` ||
99
| | [app.bsky.actor.getPreferences](https://docs.bsky.app/docs/api/app-bsky-actor-get-preferences) | `BlueskyAgent.GetPreferences()` ||
1010
| | [app.bsky.actor.getSuggestions](https://docs.bsky.app/docs/api/app-bsky-actor-get-suggestions) | `BlueskyAgent.GetSuggestions()` ||
11+
| | [app.bsky.actor.putPreferences](https://docs.bsky.app/docs/api/app-bsky-actor-put-preferences) | `BlueskyAgent.PutPreferences()` ||
1112
| | [app.bsky.actor.searchActors](https://docs.bsky.app/docs/api/app-bsky-actor-search-actors) | `BlueskyAgent.SearchActors()` ||
1213
| | [app.bsky.actor.searchActorsTypeahead](https://docs.bsky.app/docs/api/app-bsky-actor-search-actors-typeahead) | `BlueskyAgent.SearchActorsTypeahead()` ||
1314
| **Feed** | [app.bsky.feed.DescribeFeedGenerator](https://docs.bsky.app/docs/api/app-bsky-feed-describe-feed-generator) | `BlueskyAgent.DescribeFeedGenerator()` ||

docs/docs/threadGatesAndPostGates.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Thread Gates and Post Gates
22

3-
## Thread Gates
3+
## <a name="threadGates">Thread Gates</a>
44

55
Thread gates allow the original author of a thread to control who can reply to the thread, allowing people mentioned in the root post to reply,
66
people the author is following to reply, replies from actors in a list or allow no replies at all.
@@ -29,7 +29,7 @@ with `GetThreadGate()`, if that is successful update the returned`ThreadGate` cl
2929

3030
You can use `GetPostThread()` to see a view over a thread, including replies.
3131

32-
## Post Gates
32+
## <a name="postGates">Post Gates</a>
3333

3434
Post gates allow the post author to remove it from someone else's post quoting their post, and also to disable embedding on a post.
3535

docs/docs/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ items:
2626

2727
- name: Users
2828
items:
29+
- name: User Preferences
30+
href: userPreferences.md
2931
- name: Conversations & Messages
3032
href: conversationsAndMessages.md
3133
- name: Editing a user profile

docs/docs/userPreferences.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# <a name="userPreferences">User Preferences</a>
2+
3+
## Reading user preferences
4+
5+
User preferences are stored against a user's profile and can be retrieved with `agent.GetPreferences()`.
6+
7+
```c#
8+
var userPreferences = await agent.GetPreferences();
9+
```
10+
11+
The `Bluesky.Actor.Preferences` class is both a list of user preferences, but also has properties for the commonly used preferences. These include
12+
13+
* `LabelersPreference` - a list of labelers the user has subscribed to.
14+
* `ContentLabelPeference` - a list of preferences for content labelling, the DID of the labeler that produces it and the visibility of content that is labeled.
15+
* `SavedFeedPreference2` - a list of saved feeds.
16+
* `HiddenPosts` - a list of AT URIs for posts the user has hidden.
17+
* `AdultContentPreferences` - the users preferences for the display of adult content.
18+
* `FeedViewPreferences` - how the user wants to view their feeds, include settings for hiding replies, hiding replies by actors they don't follow etc.
19+
* `MutedWords` - a list of words the user does not want to see, including settings for expiry of the mute, whether if applies to everyone or just actors they don't follow, etc.
20+
* `ThreadViewPreferences` - how the user would like threads to be displayed in a client.
21+
* `InteractionPreferences` - the [thread gates](threadGatesAndPostGates.md#threadGates) and [post gates](threadGatesAndPostGates.md#postGates) the user would like applied to new threads or posts they create.
22+
23+
Most of these preferences must be implemented within your client, they are not applied on the Bluesky backend.
24+
25+
For example, the `LabelersPreference` affects the `Labels` attached to content, but you must pass it into API calls that retrieve posts and threads.
26+
27+
```c#
28+
Preferences preferences = new();
29+
var preferencesResult = await agent.GetPreferences(cancellationToken: cancellationToken);
30+
if (preferencesResult.Succeeded)
31+
{
32+
preferences = preferencesResult.Result;
33+
}
34+
35+
var timelineResult = await agent.GetTimeline(
36+
limit: pageSize,
37+
subscribedLabelers: preferences.SubscribedLabelers);
38+
```
39+
40+
The same applies to `InteractionPreferences`, which you must pass into any of the `Post` methods, or apply to a `PostBuilder`.
41+
42+
```c#
43+
var interactionPreferences = null;
44+
var userPreferences = await agent.GetPreferences(cancellationToken: cancellationToken);
45+
if (userPreferences.Succeeded)
46+
{
47+
interactionPreferences = userPreferences.Result.InteractionPreferences;
48+
}
49+
50+
await agent.Post(
51+
"Post, using default preferences, if any",
52+
interactionPreferences: interactionPreferences);
53+
```
54+
55+
For things like `MutedWords` you will need to implement the logic to filter out posts that contain muted words, or for `LabelersPreference` you
56+
need to implement the logic to label or hide according to the user preferences.
57+
58+
## Writing user preferences
59+
60+
You can write user preferences with `agent.PutPreferences()`. This method takes a `Preferences` list and will update the user's preferences.
61+
There is also an `agent.PutPreference()` should you only want to update a single preference. You do not have to supply the full list of preferences
62+
returned by `GetPreferences()` only the ones you want to change, for example
63+
64+
```c#
65+
var updatedPreference = new ThreadViewPreference()
66+
{
67+
PrioritizeFollowedUsers = true
68+
};
69+
70+
await agent.PutPreference(updatedPreference, cancellationToken: cancellationToken);
71+
```

idunno.Bluesky.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{E2B63F0A-9
140140
docs\docs\threadGatesAndPostGates.md = docs\docs\threadGatesAndPostGates.md
141141
docs\docs\timeline.md = docs\docs\timeline.md
142142
docs\docs\toc.yml = docs\docs\toc.yml
143+
docs\docs\userPreferences.md = docs\docs\userPreferences.md
143144
docs\docs\video.md = docs\docs\video.md
144145
EndProjectSection
145146
EndProject

src/idunno.AtProto/AtProtoAgent.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ public async Task<AtProtoHttpResult<ServerDescription>> DescribeServer(Uri? serv
317317
/// Thrown when <paramref name="writeRequests"/> or <paramref name="repo" /> is null.
318318
/// </exception>
319319
/// <exception cref="ArgumentException">Thrown when <paramref name="writeRequests"/> is an empty collection.</exception>
320-
/// <exception cref="AuthenticationRequiredException">Thrown when the current session is not authenticated.</exception>
320+
/// <exception cref="AuthenticationRequiredException">Thrown when the current agent is not authenticated.</exception>
321321
public async Task<AtProtoHttpResult<ApplyWritesResponse>> ApplyWrites(
322322
ICollection<ApplyWritesRequestValueBase> writeRequests,
323323
Did repo,
@@ -376,7 +376,7 @@ public async Task<AtProtoHttpResult<ApplyWritesResponse>> ApplyWrites(
376376
/// <param name="cancellationToken"><para>A cancellation token that can be used by other objects or threads to receive notice of cancellation.</para></param>
377377
/// <returns><para>The task object representing the asynchronous operation.</para></returns>
378378
/// <exception cref="ArgumentNullException"><para>Thrown when <paramref name="record"/> or <paramref name="collection"/> is null.</para></exception>
379-
/// <exception cref="AuthenticationRequiredException"><para>Thrown when the current session is not authenticated.</para></exception>
379+
/// <exception cref="AuthenticationRequiredException"><para>Thrown when the current agent is not authenticated.</para></exception>
380380
public async Task<AtProtoHttpResult<CreateRecordResponse>> CreateRecord<TRecord>(
381381
TRecord record,
382382
Nsid collection,
@@ -583,7 +583,7 @@ await AtProtoServer.DeleteRecord(
583583
/// <exception cref="ArgumentNullException">
584584
/// <para>Thrown when <paramref name="record"/>, <paramref name="collection"/>, <paramref name="creator"/> or <paramref name="rKey"/> is null.</para>
585585
/// </exception>
586-
/// <exception cref="AuthenticationRequiredException"><para>Thrown when the current session is not authenticated.</para></exception>
586+
/// <exception cref="AuthenticationRequiredException"><para>Thrown when the current agent is not authenticated.</para></exception>
587587
public async Task<AtProtoHttpResult<PutRecordResponse>> PutRecord(
588588
object record,
589589
Nsid collection,

src/idunno.AtProto/Authentication/IdentityModel.OidcClient.DPoP/DPoPExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace IdentityModel.OidcClient.DPoP;
55

6+
/// <exclude />
67
/// <summary>
78
/// Extensions for HTTP request/response messages
89
/// </summary>

0 commit comments

Comments
 (0)