Federate with wordpress, improvements for NodeBB, Discourse federation (#4692)
* Federate with wordpress * upgrade apub lib with fix * Also read post's community from `audience` * cleanup * cargo update * upgrade apub lib * add wordpress test activity
This commit is contained in:
parent
cfdc732d3a
commit
7c146272c3
11 changed files with 264 additions and 7 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -16,9 +16,9 @@ checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "activitypub_federation"
|
name = "activitypub_federation"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e54fe65c4a4b57712d8e436f1fb86ff37e10b56f011f4233fbbfa8c669163e9d"
|
checksum = "ac8ff2d0151ce9ac02eb29e4a58b41d28693f141f7963d4bfabd2f9d402ecec7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activitystreams-kinds",
|
"activitystreams-kinds",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
|
|
@ -99,7 +99,7 @@ lemmy_db_views = { version = "=0.19.4-beta.6", path = "./crates/db_views" }
|
||||||
lemmy_db_views_actor = { version = "=0.19.4-beta.6", path = "./crates/db_views_actor" }
|
lemmy_db_views_actor = { version = "=0.19.4-beta.6", path = "./crates/db_views_actor" }
|
||||||
lemmy_db_views_moderator = { version = "=0.19.4-beta.6", path = "./crates/db_views_moderator" }
|
lemmy_db_views_moderator = { version = "=0.19.4-beta.6", path = "./crates/db_views_moderator" }
|
||||||
lemmy_federate = { version = "=0.19.4-beta.6", path = "./crates/federate" }
|
lemmy_federate = { version = "=0.19.4-beta.6", path = "./crates/federate" }
|
||||||
activitypub_federation = { version = "0.5.5", default-features = false, features = [
|
activitypub_federation = { version = "0.5.6", default-features = false, features = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
] }
|
] }
|
||||||
diesel = "2.1.6"
|
diesel = "2.1.6"
|
||||||
|
|
49
crates/apub/assets/wordpress/activities/announce.json
Normal file
49
crates/apub/assets/wordpress/activities/announce.json
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
"@context": ["https://www.w3.org/ns/activitystreams"],
|
||||||
|
"id": "https://pfefferle.org/lemmy-part-4/#activity#activity",
|
||||||
|
"type": "Announce",
|
||||||
|
"audience": "https://pfefferle.org/@pfefferle.org",
|
||||||
|
"published": "2024-05-03T12:32:29Z",
|
||||||
|
"updated": "2024-05-06T08:20:33Z",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"https://pfefferle.org/wp-json/activitypub/1.0/actors/1/followers"
|
||||||
|
],
|
||||||
|
"cc": [],
|
||||||
|
"object": {
|
||||||
|
"id": "https://pfefferle.org/lemmy-part-4/#activity",
|
||||||
|
"type": "Update",
|
||||||
|
"audience": "https://pfefferle.org/@pfefferle.org",
|
||||||
|
"published": "2024-05-03T12:32:29Z",
|
||||||
|
"updated": "2024-05-06T08:20:33Z",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"https://pfefferle.org/wp-json/activitypub/1.0/actors/1/followers"
|
||||||
|
],
|
||||||
|
"cc": [],
|
||||||
|
"object": {
|
||||||
|
"id": "https://pfefferle.org/lemmy-part-4/",
|
||||||
|
"type": "Article",
|
||||||
|
"attachment": [],
|
||||||
|
"attributedTo": "https://pfefferle.org/author/pfefferle/",
|
||||||
|
"audience": "https://pfefferle.org/@pfefferle.org",
|
||||||
|
"content": "\u003Cp\u003EIdentifies one or more entities that represent the total population of entities for which the object can considered to be relevant. Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant. \u003C/p\u003E",
|
||||||
|
"contentMap": {
|
||||||
|
"en": "\u003Cp\u003EIdentifies one or more entities that represent the total population of entities for which the object can considered to be relevant. Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant. \u003C/p\u003E"
|
||||||
|
},
|
||||||
|
"name": "Lemmy (Part 4)",
|
||||||
|
"published": "2024-05-03T12:32:29Z",
|
||||||
|
"summary": "Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant. Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant.Identifies one or more entities that represent the total population of entities for which the object [...]",
|
||||||
|
"tag": [],
|
||||||
|
"updated": "2024-05-06T08:20:33Z",
|
||||||
|
"url": "https://pfefferle.org/lemmy-part-4/",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"https://pfefferle.org/wp-json/activitypub/1.0/actors/1/followers"
|
||||||
|
],
|
||||||
|
"cc": []
|
||||||
|
},
|
||||||
|
"actor": "https://pfefferle.org/author/pfefferle/"
|
||||||
|
},
|
||||||
|
"actor": "https://pfefferle.org/@pfefferle.org"
|
||||||
|
}
|
66
crates/apub/assets/wordpress/objects/group.json
Normal file
66
crates/apub/assets/wordpress/objects/group.json
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
"https://purl.archive.org/socialweb/webfinger",
|
||||||
|
{
|
||||||
|
"schema": "http://schema.org#",
|
||||||
|
"toot": "http://joinmastodon.org/ns#",
|
||||||
|
"webfinger": "https://webfinger.net/#",
|
||||||
|
"lemmy": "https://join-lemmy.org/ns#",
|
||||||
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||||
|
"PropertyValue": "schema:PropertyValue",
|
||||||
|
"value": "schema:value",
|
||||||
|
"Hashtag": "as:Hashtag",
|
||||||
|
"featured": {
|
||||||
|
"@id": "toot:featured",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"featuredTags": {
|
||||||
|
"@id": "toot:featuredTags",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"moderators": {
|
||||||
|
"@id": "lemmy:moderators",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"postingRestrictedToMods": "lemmy:postingRestrictedToMods",
|
||||||
|
"discoverable": "toot:discoverable",
|
||||||
|
"indexable": "toot:indexable",
|
||||||
|
"resource": "webfinger:resource"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://pfefferle.org/@pfefferle.org",
|
||||||
|
"type": "Group",
|
||||||
|
"attachment": [],
|
||||||
|
"attributedTo": "https://pfefferle.org/wp-json/activitypub/1.0/collections/moderators",
|
||||||
|
"name": "Matthias Pfefferle",
|
||||||
|
"icon": {
|
||||||
|
"type": "Image",
|
||||||
|
"url": "https://pfefferle.org/wp-content/uploads/2023/06/cropped-BeLItBV-_400x400.jpg"
|
||||||
|
},
|
||||||
|
"published": "2024-04-03T16:58:22Z",
|
||||||
|
"summary": "<p>Webworker, blogger und podcaster</p>\n",
|
||||||
|
"tag": [],
|
||||||
|
"url": "https://pfefferle.org/@pfefferle.org",
|
||||||
|
"inbox": "https://pfefferle.org/wp-json/activitypub/1.0/users/0/inbox",
|
||||||
|
"outbox": "https://pfefferle.org/wp-json/activitypub/1.0/users/0/outbox",
|
||||||
|
"following": "https://pfefferle.org/wp-json/activitypub/1.0/users/0/following",
|
||||||
|
"followers": "https://pfefferle.org/wp-json/activitypub/1.0/users/0/followers",
|
||||||
|
"preferredUsername": "pfefferle.org",
|
||||||
|
"endpoints": {
|
||||||
|
"sharedInbox": "https://pfefferle.org/wp-json/activitypub/1.0/inbox"
|
||||||
|
},
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://pfefferle.org/@pfefferle.org#main-key",
|
||||||
|
"owner": "https://pfefferle.org/@pfefferle.org",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuq8xeLMFcaCwPFBhgMRE\n/dDh2XKoNXFXnixctmK8BXSuuLMxucm3I/8NyhIvb3LqU+uP1fO8F0ecUbk2sN+x\nKag5vIV6yKXzJ8ILMWQ9AaELpXDmMZqL0zal0LUJRAOkDgPDovDAoq6tx++yDoV0\njdVbf9CoZKit1cz2ZrEuE5dswq3J/z9+c6POkhCkWEX5TPJzkOrmnjkvrXxGHUJ2\nA3+P+VaZhd5cmvqYosSpYNJshxCdev12pIF78OnYLiYiyXlgGHU+7uQR0M4tTcij\n6cUdLkms9m+b6H3ctXntPn410e5YLFPldjAYzQB5wHVdFZsWtyrbqfYdCa+KkKpA\nvwIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
|
},
|
||||||
|
"manuallyApprovesFollowers": false,
|
||||||
|
"featured": "https://pfefferle.org/wp-json/activitypub/1.0/users/0/collections/featured",
|
||||||
|
"moderators": "https://pfefferle.org/wp-json/activitypub/1.0/collections/moderators",
|
||||||
|
"discoverable": true,
|
||||||
|
"indexable": true,
|
||||||
|
"webfinger": "pfefferle.org@pfefferle.org",
|
||||||
|
"postingRestrictedToMods": true
|
||||||
|
}
|
24
crates/apub/assets/wordpress/objects/note.json
Normal file
24
crates/apub/assets/wordpress/objects/note.json
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
{
|
||||||
|
"Hashtag": "as:Hashtag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://pfefferle.org?c=148",
|
||||||
|
"type": "Note",
|
||||||
|
"attributedTo": "https://pfefferle.org/author/pfefferle/",
|
||||||
|
"content": "<p>Nice! Hello from WordPress!</p>",
|
||||||
|
"contentMap": {
|
||||||
|
"en": "<p>Nice! Hello from WordPress!</p>"
|
||||||
|
},
|
||||||
|
"inReplyTo": "https://socialhub.activitypub.rocks/ap/object/ce040f1ead95964f6dbbf1084b81432d",
|
||||||
|
"published": "2024-04-30T15:21:13Z",
|
||||||
|
"tag": [],
|
||||||
|
"url": "https://pfefferle.org?c=148",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"https://pfefferle.org/wp-json/activitypub/1.0/users/0/followers"
|
||||||
|
],
|
||||||
|
"cc": []
|
||||||
|
}
|
26
crates/apub/assets/wordpress/objects/page.json
Normal file
26
crates/apub/assets/wordpress/objects/page.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
{
|
||||||
|
"Hashtag": "as:Hashtag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://pfefferle.org/this-is-a-test-federation/",
|
||||||
|
"type": "Article",
|
||||||
|
"attachment": [],
|
||||||
|
"attributedTo": "https://pfefferle.org/author/pfefferle/",
|
||||||
|
"content": "<p>with Discource!</p>",
|
||||||
|
"contentMap": {
|
||||||
|
"en": "<p>with Discource!</p>"
|
||||||
|
},
|
||||||
|
"name": "This is a test-federation",
|
||||||
|
"published": "2024-04-30T15:16:41Z",
|
||||||
|
"summary": "with Discource! [...]",
|
||||||
|
"tag": [],
|
||||||
|
"url": "https://pfefferle.org/this-is-a-test-federation/",
|
||||||
|
"to": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"https://pfefferle.org/wp-json/activitypub/1.0/users/1/followers"
|
||||||
|
],
|
||||||
|
"cc": []
|
||||||
|
}
|
74
crates/apub/assets/wordpress/objects/person.json
Normal file
74
crates/apub/assets/wordpress/objects/person.json
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
"https://purl.archive.org/socialweb/webfinger",
|
||||||
|
{
|
||||||
|
"schema": "http://schema.org#",
|
||||||
|
"toot": "http://joinmastodon.org/ns#",
|
||||||
|
"webfinger": "https://webfinger.net/#",
|
||||||
|
"lemmy": "https://join-lemmy.org/ns#",
|
||||||
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||||
|
"PropertyValue": "schema:PropertyValue",
|
||||||
|
"value": "schema:value",
|
||||||
|
"Hashtag": "as:Hashtag",
|
||||||
|
"featured": {
|
||||||
|
"@id": "toot:featured",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"featuredTags": {
|
||||||
|
"@id": "toot:featuredTags",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"moderators": {
|
||||||
|
"@id": "lemmy:moderators",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"postingRestrictedToMods": "lemmy:postingRestrictedToMods",
|
||||||
|
"discoverable": "toot:discoverable",
|
||||||
|
"indexable": "toot:indexable",
|
||||||
|
"resource": "webfinger:resource"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://pfefferle.org/author/pfefferle/",
|
||||||
|
"type": "Person",
|
||||||
|
"attachment": [
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Blog",
|
||||||
|
"value": "<a rel=\"me\" title=\"https://pfefferle.org/\" target=\"_blank\" href=\"https://pfefferle.org/\">pfefferle.org</a>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Profile",
|
||||||
|
"value": "<a rel=\"me\" title=\"https://pfefferle.org/author/pfefferle/\" target=\"_blank\" href=\"https://pfefferle.org/author/pfefferle/\">pfefferle.org</a>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Matthias Pfefferle",
|
||||||
|
"icon": {
|
||||||
|
"type": "Image",
|
||||||
|
"url": "https://secure.gravatar.com/avatar/a2bdca7870e859658cece96c044b3be5?s=120&d=mm&r=g"
|
||||||
|
},
|
||||||
|
"published": "2014-02-10T15:23:08Z",
|
||||||
|
"summary": "<p>Ich arbeite als Open Web Lead für Automattic.</p>\n",
|
||||||
|
"tag": [],
|
||||||
|
"url": "https://pfefferle.org/author/pfefferle/",
|
||||||
|
"inbox": "https://pfefferle.org/wp-json/activitypub/1.0/users/1/inbox",
|
||||||
|
"outbox": "https://pfefferle.org/wp-json/activitypub/1.0/users/1/outbox",
|
||||||
|
"following": "https://pfefferle.org/wp-json/activitypub/1.0/users/1/following",
|
||||||
|
"followers": "https://pfefferle.org/wp-json/activitypub/1.0/users/1/followers",
|
||||||
|
"preferredUsername": "matthias",
|
||||||
|
"endpoints": {
|
||||||
|
"sharedInbox": "https://pfefferle.org/wp-json/activitypub/1.0/inbox"
|
||||||
|
},
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://pfefferle.org/author/pfefferle/#main-key",
|
||||||
|
"owner": "https://pfefferle.org/author/pfefferle/",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvTA5RA40nOsso04RSwyX\nHXTojRPUMlIlArDcSy3M5GUJp9/xbxSUOdBjqd31KKB1GIi3vrLmD1Qi/ZqS95Qy\nw2Zd3xOsCg+o9bsyOG+O6Y8Lu+HEB5JKLUbNHdiSviakJ8wGadH9Wm4WIiN20y+q\n/u6lgxgiWfZ2CFCN6SOc28fUKi9NmKvXK+M12BhFfy1tC5KWXKDm0UbfI1+dmqhR\n3Ffe6vEsCI/YIVVdWxQ9kouOd0XSHOGdslktkepRO7IP9i9TdwyeCa0WWRoeO5Wa\ntVpc1Y0WuNbTM2ksIXTg0G+rO1/6KO/hrHnGu3RCfb/ZIHK5L/aWYb9B3PG3LyKV\n+wIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
|
},
|
||||||
|
"manuallyApprovesFollowers": false,
|
||||||
|
"featured": "https://pfefferle.org/wp-json/activitypub/1.0/users/1/collections/featured",
|
||||||
|
"discoverable": true,
|
||||||
|
"indexable": true,
|
||||||
|
"webfinger": "matthias@pfefferle.org"
|
||||||
|
}
|
|
@ -96,4 +96,10 @@ mod tests {
|
||||||
test_json::<Report>("assets/mbin/activities/flag.json")?;
|
test_json::<Report>("assets/mbin/activities/flag.json")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_wordpress_activities() -> LemmyResult<()> {
|
||||||
|
test_json::<AnnounceActivity>("assets/wordpress/activities/announce.json")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,4 +206,13 @@ mod tests {
|
||||||
test_json::<Person>("assets/nodebb/objects/person.json")?;
|
test_json::<Person>("assets/nodebb/objects/person.json")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_object_wordpress() -> LemmyResult<()> {
|
||||||
|
test_json::<Group>("assets/wordpress/objects/group.json")?;
|
||||||
|
test_json::<Page>("assets/wordpress/objects/page.json")?;
|
||||||
|
test_json::<Person>("assets/wordpress/objects/person.json")?;
|
||||||
|
test_json::<Note>("assets/wordpress/objects/note.json")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,6 +233,10 @@ impl ActivityHandler for Page {
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl InCommunity for Page {
|
impl InCommunity for Page {
|
||||||
async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<ApubCommunity> {
|
async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<ApubCommunity> {
|
||||||
|
if let Some(audience) = &self.audience {
|
||||||
|
return audience.dereference(context).await;
|
||||||
|
}
|
||||||
|
|
||||||
let community = match &self.attributed_to {
|
let community = match &self.attributed_to {
|
||||||
AttributedTo::Lemmy(_) => {
|
AttributedTo::Lemmy(_) => {
|
||||||
let mut iter = self.to.iter().merge(self.cc.iter());
|
let mut iter = self.to.iter().merge(self.cc.iter());
|
||||||
|
@ -243,7 +247,7 @@ impl InCommunity for Page {
|
||||||
break c;
|
break c;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyErrorType::NoCommunityFoundInCc)?
|
Err(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,11 +255,12 @@ impl InCommunity for Page {
|
||||||
p.iter()
|
p.iter()
|
||||||
.find(|a| a.kind == PersonOrGroupType::Group)
|
.find(|a| a.kind == PersonOrGroupType::Group)
|
||||||
.map(|a| ObjectId::<ApubCommunity>::from(a.id.clone().into_inner()))
|
.map(|a| ObjectId::<ApubCommunity>::from(a.id.clone().into_inner()))
|
||||||
.ok_or(LemmyErrorType::PageDoesNotSpecifyGroup)?
|
.ok_or(LemmyErrorType::CouldntFindCommunity)?
|
||||||
.dereference(context)
|
.dereference(context)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(audience) = &self.audience {
|
if let Some(audience) = &self.audience {
|
||||||
verify_community_matches(audience, community.actor_id.clone())?;
|
verify_community_matches(audience, community.actor_id.clone())?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,8 +99,6 @@ pub enum LemmyErrorType {
|
||||||
PersonIsBannedFromSite(String),
|
PersonIsBannedFromSite(String),
|
||||||
InvalidVoteValue,
|
InvalidVoteValue,
|
||||||
PageDoesNotSpecifyCreator,
|
PageDoesNotSpecifyCreator,
|
||||||
PageDoesNotSpecifyGroup,
|
|
||||||
NoCommunityFoundInCc,
|
|
||||||
NoEmailSetup,
|
NoEmailSetup,
|
||||||
LocalSiteNotSetup,
|
LocalSiteNotSetup,
|
||||||
EmailSmtpServerNeedsAPort,
|
EmailSmtpServerNeedsAPort,
|
||||||
|
|
Loading…
Reference in a new issue