federation block routing

This commit is contained in:
f0x 2022-09-15 21:16:18 +02:00
parent 9fbe8f5cfd
commit 80c05825ab
7 changed files with 150 additions and 47 deletions

View file

@ -21,62 +21,108 @@
const Promise = require("bluebird"); const Promise = require("bluebird");
const React = require("react"); const React = require("react");
const Redux = require("react-redux"); const Redux = require("react-redux");
const {Switch, Route, Link, useRoute} = require("wouter");
const Submit = require("../components/submit"); const Submit = require("../components/submit");
const api = require("../lib/api"); const api = require("../lib/api");
const adminActions = require("../redux/reducers/instances").actions; const adminActions = require("../redux/reducers/instances").actions;
const { const base = "/settings/admin/federation";
TextInput,
TextArea, // const {
File // TextInput,
} = require("../components/form-fields").formFields(adminActions.setAdminSettingsVal, (state) => state.instances.adminSettings); // TextArea,
// File
// } = require("../components/form-fields").formFields(adminActions.setAdminSettingsVal, (state) => state.instances.adminSettings);
module.exports = function AdminSettings() { module.exports = function AdminSettings() {
const dispatch = Redux.useDispatch(); const dispatch = Redux.useDispatch();
const instance = Redux.useSelector(state => state.instances.adminSettings); // const instance = Redux.useSelector(state => state.instances.adminSettings);
const { blockedInstances } = Redux.useSelector(state => state.admin);
const [loaded, setLoaded] = React.useState(false);
const [errorMsg, setError] = React.useState(""); const [errorMsg, setError] = React.useState("");
const [statusMsg, setStatus] = React.useState(""); const [statusMsg, setStatus] = React.useState("");
React.useEffect(() => { const [loaded, setLoaded] = React.useState(false);
Promise.try(() => {
return dispatch(api.admin.fetchDomainBlocks());
}).then(() => {
setLoaded(true);
}).catch((e) => {
console.log(e);
});
}, []);
function submit() { React.useEffect(() => {
setStatus("PATCHing"); if (blockedInstances != undefined) {
setError(""); setLoaded(true);
return Promise.try(() => { } else {
return dispatch(api.admin.updateInstance()); return Promise.try(() => {
}).then(() => { return dispatch(api.admin.fetchDomainBlocks());
setStatus("Saved!"); }).then(() => {
}).catch((e) => { setLoaded(true);
setError(e.message); });
setStatus(""); }
}); }, []);
}
if (!loaded) { if (!loaded) {
return ( return (
<div> <div>
<h1>Federation</h1> <h1>Federation</h1>
Loading instance blocks... Loading...
</div> </div>
); );
} }
return ( return (
<div> <div>
<h1>Federation</h1> <Switch>
<Route path={`${base}/:domain`}>
<InstancePage blockedInstances={blockedInstances}/>
</Route>
<InstanceOverview blockedInstances={blockedInstances} />
</Switch>
</div> </div>
); );
}; };
function InstanceOverview({blockedInstances}) {
return (
<div>
<h1>Federation</h1>
{blockedInstances.map((entry) => {
return (
<Link key={entry.domain} to={`${base}/${entry.domain}`}>
<a>{entry.domain}</a>
</Link>
);
})}
</div>
);
}
function BackButton() {
return (
<Link to={base}>
<a className="button">&lt; back</a>
</Link>
);
}
function InstancePage({blockedInstances}) {
let [_match, {domain}] = useRoute(`${base}/:domain`);
let [status, setStatus] = React.useState("");
let [entry, setEntry] = React.useState(() => {
let entry = blockedInstances.find((a) => a.domain == domain);
if (entry == undefined) {
setStatus(`No block entry found for ${domain}, but you can create one below:`);
return {
private_comment: ""
};
} else {
return entry;
}
});
return (
<div>
{status}
<h1><BackButton/> Federation settings for: {domain}</h1>
<div>{entry.private_comment}</div>
</div>
);
}

View file

@ -22,7 +22,7 @@ const React = require("react");
const { Link, useRoute } = require("wouter"); const { Link, useRoute } = require("wouter");
module.exports = function NavButton({href, name}) { module.exports = function NavButton({href, name}) {
const [isActive] = useRoute(href); const [isActive] = useRoute(`${href}/:anything?`);
return ( return (
<Link href={href}> <Link href={href}>
<a className={isActive ? "active" : ""} data-content={name}> <a className={isActive ? "active" : ""} data-content={name}>

View file

@ -21,6 +21,7 @@
const Promise = require("bluebird"); const Promise = require("bluebird");
const instance = require("../../redux/reducers/instances").actions; const instance = require("../../redux/reducers/instances").actions;
const admin = require("../../redux/reducers/admin").actions;
module.exports = function ({ apiCall, getChanges }) { module.exports = function ({ apiCall, getChanges }) {
return { return {
@ -45,6 +46,8 @@ module.exports = function ({ apiCall, getChanges }) {
return function (dispatch, _getState) { return function (dispatch, _getState) {
return Promise.try(() => { return Promise.try(() => {
return dispatch(apiCall("GET", "/api/v1/admin/domain_blocks")); return dispatch(apiCall("GET", "/api/v1/admin/domain_blocks"));
}).then((data) => {
return dispatch(admin.setBlockedInstances(data));
}); });
}; };
} }

View file

@ -24,7 +24,7 @@ const { OAUTHError, AuthenticationError } = require("../errors");
const oauth = require("../../redux/reducers/oauth").actions; const oauth = require("../../redux/reducers/oauth").actions;
const temporary = require("../../redux/reducers/temporary").actions; const temporary = require("../../redux/reducers/temporary").actions;
const user = require("../../redux/reducers/user").actions; const admin = require("../../redux/reducers/admin").actions;
module.exports = function oauthAPI({ apiCall, getCurrentUrl }) { module.exports = function oauthAPI({ apiCall, getCurrentUrl }) {
return { return {
@ -103,8 +103,11 @@ module.exports = function oauthAPI({ apiCall, getCurrentUrl }) {
// no role info, try fetching an admin-only route and see if we get an error // no role info, try fetching an admin-only route and see if we get an error
return Promise.try(() => { return Promise.try(() => {
return dispatch(apiCall("GET", "/api/v1/admin/domain_blocks")); return dispatch(apiCall("GET", "/api/v1/admin/domain_blocks"));
}).then(() => { }).then((data) => {
return dispatch(oauth.setAdmin(true)); return Promise.all([
dispatch(oauth.setAdmin(true)),
dispatch(admin.setBlockedInstances(data))
]);
}).catch(AuthenticationError, () => { }).catch(AuthenticationError, () => {
return dispatch(oauth.setAdmin(false)); return dispatch(oauth.setAdmin(false));
}).catch((e) => { }).catch((e) => {

View file

@ -64,11 +64,11 @@ module.exports = function getViews(struct) {
let url = `${base}/${urlSafe(name)}`; let url = `${base}/${urlSafe(name)}`;
if (firstRoute == undefined) { if (firstRoute == undefined) {
firstRoute = `${base}/${urlSafe(name)}`; firstRoute = url;
} }
routes.push(( panelRouterEl.push((
<Route path={url} key={url}> <Route path={`${url}/:page?`} key={url}>
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => { }}> <ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => { }}>
{/* FIXME: implement onReset */} {/* FIXME: implement onReset */}
<ViewComponent /> <ViewComponent />
@ -87,14 +87,15 @@ module.exports = function getViews(struct) {
</Route> </Route>
); );
let childrenPath = `${base}/:section`; // let childrenPath = `${base}/:section`;
panelRouterEl.push( // panelRouterEl.push(...routes);
<Route key={childrenPath} path={childrenPath}> console.log(panelRouterEl);
<Switch> // <Route key={childrenPath} path={childrenPath}>
{routes} // <Switch id="childrenPath-switch">
</Switch> // {routes}
</Route> // </Switch>
); // </Route>
// );
sidebarEl.push( sidebarEl.push(
<React.Fragment key={name}> <React.Fragment key={name}>

View file

@ -36,6 +36,7 @@ const combinedReducers = combineReducers({
instances: require("./reducers/instances").reducer, instances: require("./reducers/instances").reducer,
temporary: require("./reducers/temporary").reducer, temporary: require("./reducers/temporary").reducer,
user: require("./reducers/user").reducer, user: require("./reducers/user").reducer,
admin: require("./reducers/admin").reducer,
}); });
const persistedReducer = persistReducer(persistConfig, combinedReducers); const persistedReducer = persistReducer(persistConfig, combinedReducers);

View file

@ -0,0 +1,49 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
const {createSlice} = require("@reduxjs/toolkit");
// const d = require("dotty");
function sortBlocks(blocks) {
return blocks.sort((a, b) => { // alphabetical sort
return a.domain.localeCompare(b.domain);
});
}
// function deduplicateBlocks(blocks) {
// let a = new Map();
// blocks.forEach((block) => {
// a.set(block.id, block);
// });
// return Array.from(a.values());
// }
module.exports = createSlice({
name: "admin",
initialState: {
blockedInstances: undefined,
blockedInstancesMap: {}
},
reducers: {
setBlockedInstances: (state, {payload}) => {
state.blockedInstances = sortBlocks(payload);
},
}
});