C55X6B5YBXZ7SVRC4IDCRG6BY5ZW2V6JORGQ2WMQPBAECVLMZOMQC
6CUC3C5BCSMUJU73T3XYWPTVEUYXXG3PREA7P2BRZZ7XZY54JBMAC
OWZCU6OX33FKWEEI7LUWIZZTBPUP2OSLJIADPHIBYOWGPPRIPMIAC
B7W4Q522DLB6DKH2TFDOCTSZFZLFTOLCT6CCZEOC3V3UUMSAOOFAC
AJKCAY3ODMTFBO6GXWXWQSWNFIH3H7JNBRFVW5H6ZSWA7SZGY3FAC
Q4BYGYNX3UZXX47EMX2GWX6M6ICSMIMCLQ7HVOYS4HB4RHYI4NEQC
4C7QXSEQ7XGPZDLCUTFSDCORVEMIRVD55IZTCTP6W4QQCCI52CZQC
GGREOYIRZE2GH62X7YXQA7IUSSB25ENLQ5OKVJYWPNI462DP37FAC
EKERBH2GMXCDZSFXAQP6FGGQTTW3ZENOUM4ZKZVHWAAKGW64YLTAC
.json::<WclToken>()
.await
.map_err(anyhow::Error::from)
.json::<TokenResponse>()
.await?;
match res {
TokenResponse::Ok(token) => Ok(token),
TokenResponse::Err(err) => {
error!("an error occurred while refreshing a user token: {:?}", err);
return Err(anyhow!("unable to refresh token"));
}
}
.json::<WclToken>()
.await
.map_err(anyhow::Error::from)
.json::<TokenResponse>()
.await?;
match res {
TokenResponse::Ok(token) => Ok(token),
TokenResponse::Err(err) => {
error!("an error occurred while acquiring a user token: {:?}", err);
return Err(anyhow!("unable to acquire token"));
}
}
}
/// Whether we have access to private logs for `guild` / `zone`.
async fn private_access(&self, ctx: &Context<'_>, guild: i32, zone: i32) -> Result<bool> {
use crate::schema::auth_codes::dsl as auth;
let Data { conpool, .. } = ctx.data()?;
Ok(auth::auth_codes
.filter(auth::team.eq(guild).and(auth::zone.eq(zone)))
.count()
.get_result::<i64>(&*conpool.get()?)?
> 0)
async fn revoke_team(&self, ctx: &Context<'_>, code: String, team: i64) -> Result<bool> {
todo!()
async fn revoke_team(
&self,
ctx: &Context<'_>,
code: String,
team: i64,
zone: i64,
) -> Result<bool> {
use crate::schema::{auth_codes::dsl as auth, teams::dsl as teams};
let Data {
client,
conpool,
secrets,
..
} = ctx.data()?;
let token = crate::user_auth::token_for_code(&client, &secrets, &code).await?;
if !user_validation::privileged_user(&client, &token, team, zone).await? {
return Ok(false);
}
let con = conpool.get()?;
con.transaction::<_, anyhow::Error, _>(|| {
// it says team, it means guild.
diesel::delete(auth::auth_codes.filter(auth::team.eq(team as i32))).execute(&con)?;
// not liking the extra round-trips here but w/e
let (guild_name, region, server): (String, String, String) = teams::teams
.filter(teams::id.eq(team as i32))
.select((teams::name, teams::region_slug, teams::server_slug))
.first(&con)?;
diesel::delete(
teams::teams.filter(
teams::name
.eq(guild_name)
.and(teams::region_slug.eq(region))
.and(teams::server_slug.eq(server)),
),
)
.execute(&con)?;
Ok(())
})?;
Ok(true)
-- Your SQL goes here
alter table team_stats
drop constraint team_stats_team_fkey,
add constraint team_stats_team_fkey foreign key (team) references teams(id) on delete cascade;
alter table encounter_stats
drop constraint encounter_stats_team_fkey,
add constraint encounter_stats_team_fkey foreign key (team) references teams(id) on delete cascade;
alter table fights
drop constraint fights_log_fkey,
add constraint fights_log_fkey foreign key (log) references logs(iid) on delete cascade;
alter table logs
drop constraint logs_team_fkey,
add constraint logs_team_fkey foreign key (team) references teams(iid) on delete cascade;
alter table raid_nights
drop constraint raid_nights_ts_fkey,
add constraint raid_nights_ts_fkey foreign key (ts) references team_stats(id) on delete cascade;
-- This file should undo anything in `up.sql`
alter table team_stats
drop constraint team_stats_team_fkey,
add constraint team_stats_team_fkey foreign key (team) references teams(id);
alter table encounter_stats
drop constraint encounter_stats_team_fkey,
add constraint encounter_stats_team_fkey foreign key (team) references teams(id);
alter table fights
drop constraint fights_log_fkey,
add constraint fights_log_fkey foreign key (log) references logs(iid);
alter table logs
drop constraint logs_team_fkey,
add constraint logs_team_fkey foreign key (team) references teams(iid);
alter table raid_nights
drop constraint raid_nights_ts_fkey,
add constraint raid_nights_ts_fkey foreign key (ts) references team_stats(id);
export let host = 'prog-stats.emallson.net';
if (process.env.NODE_ENV === 'development') {
host = 'localhost:9998';
}
export function PreAuth({ open, close, guild, zone }: { open: boolean; close: () => void; guild: number; zone: number; }) {
const modalStyle = {content: { top: 'calc(50% - 20em)', bottom: 'auto', left: 'calc(50% - 20em)', width: 'min(40em, 90vw)' }};
export function PreAuth({ open, close, guild, zone }: Props) {
<Modal isOpen={open} contentLabel="Authorization Required" style={{content: { top: 'calc(50% - 20em)', bottom: 'auto', left: 'calc(50% - 20em)', width: 'min(40em, 90vw)' }}}>
<Modal isOpen={open} contentLabel="Authorization Required" style={modalStyle}>
<button onClick={redirect.bind(null, guild, zone)} className="py-2 px-4 bg-blue-200 font-bold rounded-lg shadow-md hover:bg-blue-300 focus:outline-none focus:ring-2">Continue</button>
<button onClick={redirect.bind(null, guild, zone, 'authorize')} className="py-2 px-4 bg-blue-200 font-bold rounded-lg shadow-md hover:bg-blue-300 focus:outline-none focus:ring-2">Continue</button>
export function RevokeAuth({ open, close, guild, zone }: Props) {
return (
<Modal isOpen={open} contentLabel="Revoke Access?" style={modalStyle}>
<header className="mb-2">
<legend className="font-serif text-2xl">Revoke Private Log Access</legend>
</header>
<p>
In order to revoke access to private logs, you will need to grant access via WarcraftLogs so that we can verify your identity.
</p>
<p className="mt-2">
After verification, all data related to this <strong>guild</strong> will be deleted.
</p>
<footer className="grid gap-4 justify-end grid-flow-col mt-2">
<button className="underline" onClick={close}>Cancel</button>
<button onClick={redirect.bind(null, guild, zone, 'revoke')} className="py-2 px-4 bg-red-200 font-bold rounded-lg shadow-md hover:bg-red-300 focus:outline-none focus:ring-2">Revoke Access</button>
</footer>
</Modal>
)
}
export default function Auth() {
const query = new URLSearchParams(useLocation().search);
const state = JSON.parse(window.localStorage.getItem('auth_state') || '{}');
const nonce = query.get('state');
const code = query.get('code');
const REVOKE = gql`
mutation Revoke($team: Int!, $code: String!, $zone: Int!) {
revokeTeam(code: $code, team: $team, zone: $zone)
}
`;
interface AuthProps {
code: string;
team: number;
zone: number;
pathname: string;
}
const [storeCode, { data, loading, error }] = useMutation(STORE_CODE, { onError: (e) => console.log(e) });
function RequestAccess({ code, team, zone, pathname }: AuthProps) {
console.log(code, team, zone);
const [storeCode, { called, data, loading, error }] = useMutation(STORE_CODE, { onError: (e) => console.log(e) });
console.log(called);
if(!code || state.state !== nonce) {
return <div>Invalid authorization state.</div>;
if(data && data.storeCode) {
return <Redirect to={pathname} />;
} else if(data) {
return <div>You do not have access to private or unlisted logs for that guild.</div>;
return <div></div>;
}
function RevokeAccess({ code, team, zone }: AuthProps) {
const [revokeTeam, { called, data, loading, error }] = useMutation(REVOKE, { onError: (e) => console.log(e) });
useEffect(() => {
if(!called) {
revokeTeam({ variables: { code, team, zone }});
}
}, [code, team, zone]) // eslint-disable-line react-hooks/exhaustive-deps
export default function Auth() {
const query = new URLSearchParams(useLocation().search);
const state = JSON.parse(window.localStorage.getItem('auth_state') || '{}');
const nonce = query.get('state');
const code = query.get('code');
if(!code || state.state !== nonce) {
return <div>Invalid authorization state.</div>;
}
switch(state.kind) {
case 'revoke':
return <RevokeAccess code={code} team={state.team} zone={state.zone} pathname={state.pathname} />;
case 'authorize':
return <RequestAccess code={code} team={state.team} zone={state.zone} pathname={state.pathname} />;
default:
return null;
}
}