Compare commits

...

2 commits

14 changed files with 136 additions and 8 deletions

View file

@ -133,6 +133,20 @@ impl Settings {
fs::read_to_string(CONFIG_FILE) fs::read_to_string(CONFIG_FILE)
} }
pub fn get_allowed_instances(&self) -> Vec<String> {
let mut allowed_instances: Vec<String> = self
.federation
.allowed_instances
.split(',')
.map(|d| d.to_string())
.collect();
// The defaults.hjson config always returns a [""]
allowed_instances.retain(|d| !d.eq(""));
allowed_instances
}
pub fn save_config_file(data: &str) -> Result<String, Error> { pub fn save_config_file(data: &str) -> Result<String, Error> {
fs::write(CONFIG_FILE, data)?; fs::write(CONFIG_FILE, data)?;

View file

@ -130,6 +130,7 @@ pub struct GetSiteResponse {
pub online: usize, pub online: usize,
version: String, version: String,
my_user: Option<User_>, my_user: Option<User_>,
federated_instances: Vec<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -433,6 +434,7 @@ impl Perform for Oper<GetSite> {
online, online,
version: version::VERSION.to_string(), version: version::VERSION.to_string(),
my_user, my_user,
federated_instances: Settings::get().get_allowed_instances(),
}) })
} }
} }
@ -659,6 +661,7 @@ impl Perform for Oper<TransferSite> {
online: 0, online: 0,
version: version::VERSION.to_string(), version: version::VERSION.to_string(),
my_user: Some(user), my_user: Some(user),
federated_instances: Settings::get().get_allowed_instances(),
}) })
} }
} }

View file

@ -70,12 +70,8 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
return Err(anyhow!("invalid apub id scheme: {:?}", apub_id.scheme()).into()); return Err(anyhow!("invalid apub id scheme: {:?}", apub_id.scheme()).into());
} }
let mut allowed_instances: Vec<String> = Settings::get() let mut allowed_instances: Vec<String> = Settings::get().get_allowed_instances();
.federation
.allowed_instances
.split(',')
.map(|d| d.to_string())
.collect();
// need to allow this explicitly because apub activities might contain objects from our local // need to allow this explicitly because apub activities might contain objects from our local
// instance. replace is needed to remove the port in our federation test setup. // instance. replace is needed to remove the port in our federation test setup.
let settings = Settings::get(); let settings = Settings::get();

View file

@ -40,7 +40,8 @@ pub fn config(cfg: &mut web::ServiceConfig) {
) )
.route("/search", web::get().to(index)) .route("/search", web::get().to(index))
.route("/sponsors", web::get().to(index)) .route("/sponsors", web::get().to(index))
.route("/password_change/{token}", web::get().to(index)); .route("/password_change/{token}", web::get().to(index))
.route("/instances", web::get().to(index));
} }
async fn index() -> Result<NamedFile, Error> { async fn index() -> Result<NamedFile, Error> {

View file

@ -48,6 +48,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
banned: [], banned: [],
online: null, online: null,
version: null, version: null,
federated_instances: null,
}, },
siteConfigForm: { siteConfigForm: {
config_hjson: null, config_hjson: null,

View file

@ -51,6 +51,11 @@ export class Footer extends Component<any, FooterState> {
{i18n.t('modlog')} {i18n.t('modlog')}
</Link> </Link>
</li> </li>
<li class="nav-item">
<Link class="nav-link" to="/instances">
{i18n.t('instances')}
</Link>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href={'/docs/index.html'}> <a class="nav-link" href={'/docs/index.html'}>
{i18n.t('docs')} {i18n.t('docs')}

98
ui/src/components/instances.tsx vendored Normal file
View file

@ -0,0 +1,98 @@
import { Component } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
import {
UserOperation,
WebSocketJsonResponse,
GetSiteResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
import { wsJsonToRes, toast } from '../utils';
import { i18n } from '../i18next';
interface InstancesState {
loading: boolean;
siteRes: GetSiteResponse;
}
export class Instances extends Component<any, InstancesState> {
private subscription: Subscription;
private emptyState: InstancesState = {
loading: true,
siteRes: undefined,
};
constructor(props: any, context: any) {
super(props, context);
this.state = this.emptyState;
this.subscription = WebSocketService.Instance.subject
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
.subscribe(
msg => this.parseMessage(msg),
err => console.error(err),
() => console.log('complete')
);
WebSocketService.Instance.getSite();
}
componentWillUnmount() {
this.subscription.unsubscribe();
}
get documentTitle(): string {
if (this.state.siteRes) {
return `${i18n.t('instances')} - ${this.state.siteRes.site.name}`;
} else {
return 'Lemmy';
}
}
render() {
return (
<div class="container">
<Helmet title={this.documentTitle} />
{this.state.loading ? (
<h5 class="">
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
</h5>
) : (
<div>
<h5>{i18n.t('linked_instances')}</h5>
{this.state.siteRes &&
this.state.siteRes.federated_instances.length ? (
<ul>
{this.state.siteRes.federated_instances.map(i => (
<li>
<a href={`https://${i}`} target="_blank" rel="noopener">
{i}
</a>
</li>
))}
</ul>
) : (
<div>{i18n.t('none_found')}</div>
)}
</div>
)}
</div>
);
}
parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
let res = wsJsonToRes(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
return;
} else if (res.op == UserOperation.GetSite) {
let data = res.data as GetSiteResponse;
this.state.siteRes = data;
this.state.loading = false;
this.setState(this.state);
}
}
}

View file

@ -114,6 +114,7 @@ export class Main extends Component<any, MainState> {
banned: [], banned: [],
online: null, online: null,
version: null, version: null,
federated_instances: null,
}, },
showEditSite: false, showEditSite: false,
loading: true, loading: true,

View file

@ -82,6 +82,7 @@ export class Navbar extends Component<any, NavbarState> {
banned: [], banned: [],
online: null, online: null,
version: null, version: null,
federated_instances: null,
}, },
searchParam: '', searchParam: '',
toggleSearch: false, toggleSearch: false,

View file

@ -97,6 +97,7 @@ export class Post extends Component<any, PostState> {
}, },
online: null, online: null,
version: null, version: null,
federated_instances: undefined,
}, },
}; };

View file

@ -142,6 +142,7 @@ export class User extends Component<any, UserState> {
}, },
version: undefined, version: undefined,
my_user: undefined, my_user: undefined,
federated_instances: undefined,
}, },
}; };

2
ui/src/index.tsx vendored
View file

@ -19,6 +19,7 @@ import { AdminSettings } from './components/admin-settings';
import { Inbox } from './components/inbox'; import { Inbox } from './components/inbox';
import { Search } from './components/search'; import { Search } from './components/search';
import { Sponsors } from './components/sponsors'; import { Sponsors } from './components/sponsors';
import { Instances } from './components/instances';
import { Symbols } from './components/symbols'; import { Symbols } from './components/symbols';
import { i18n } from './i18next'; import { i18n } from './i18next';
@ -89,6 +90,7 @@ class Index extends Component<any, any> {
path={`/password_change/:token`} path={`/password_change/:token`}
component={PasswordChange} component={PasswordChange}
/> />
<Route path={`/instances`} component={Instances} />
</Switch> </Switch>
<Symbols /> <Symbols />
</div> </div>

View file

@ -867,6 +867,7 @@ export interface GetSiteResponse {
online: number; online: number;
version: string; version: string;
my_user?: User; my_user?: User;
federated_instances: Array<string>;
} }
export interface SiteResponse { export interface SiteResponse {

View file

@ -294,5 +294,8 @@
"invalid_post_title": "Invalid post title", "invalid_post_title": "Invalid post title",
"invalid_url": "Invalid URL.", "invalid_url": "Invalid URL.",
"play_captcha_audio": "Play Captcha Audio", "play_captcha_audio": "Play Captcha Audio",
"bio": "Bio" "bio": "Bio",
"instances": "Instances",
"linked_instances": "Linked Instances",
"none_found": "None found."
} }