import React, {Component, PureComponent} from 'react'; import {SafeTextarea} from './Common'; import md5 from 'md5'; import './UserAction.css'; import {API_BASE} from './Common'; const LOGIN_BASE=window.location.protocol==='https:' ? '/login_proxy' : 'http://www.pkuhelper.com/services/login'; const MAX_IMG_PX=2000; const MAX_IMG_FILESIZE=256000; const ISOP_APPKEY='0feb3a8a831e11e8933a0050568508a5'; const ISOP_APPCODE='0fec960a831e11e8933a0050568508a5'; const ISOP_SVCID='PERSON_BASE_INFO,STUDENT_SCORE,STUDENT_COURSE_TABLE,STUDENT_COURSE_TABLE_ROOM,CARD_BALANCE'; export const TokenCtx=React.createContext({ value: null, set_value: ()=>{}, }); export class LoginForm extends Component { constructor(props) { super(props); this.state={ loading_status: 'done', }; this.username_ref=React.createRef(); this.password_ref=React.createRef(); } do_sendcode() { if(this.state.loading_status==='loading') return; let param= 'user='+this.username_ref.current.value+ '&svcId='+ISOP_SVCID+ '&appKey='+ISOP_APPKEY+ '×tamp='+(+new Date()); fetch( 'https://isop.pku.edu.cn/svcpub/svc/oauth/validcode?'+param+ '&msg='+md5(param+ISOP_APPCODE), {mode: 'no-cors'} ); alert('短信验证码应该会发到您的手机上,请注意查收!'); } do_login(set_token) { if(this.state.loading_status==='loading') return; this.setState({ loading_status: 'loading', }); let data=new URLSearchParams(); data.append('username', this.username_ref.current.value); data.append('valid_code', this.password_ref.current.value); data.append('isnewloginflow', 'true'); fetch(LOGIN_BASE+'/login.php?platform=hole_xmcp_ml', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: data, }) .then((res)=>res.json()) .then((json)=>{ if(json.code!==0) { if(json.msg) alert(json.msg); throw new Error(json); } set_token(json.token); alert(`成功以 ${json.name} 的身份登录`); this.setState({ loading_status: 'done', }); }) .catch((e)=>{ alert('登录失败'); this.setState({ loading_status: 'done', }); console.error(e); }); } render() { return ( {(token)=>
{token.value ?

您已登录。

Token: {token.value||'(null)'}
请勿泄露 Token,它代表您的登录状态,与您的账户唯一对应且泄露后无法重置

:

登录后可以使用关注、回复等功能

登录请求会被发送到北大统一验证接口和 PKU Helper 服务器
我们不会记录或使用您的登录信息

}
}
) } } export class ReplyForm extends Component { constructor(props) { super(props); this.state={ text: '', loading_status: 'done', }; this.on_change_bound=this.on_change.bind(this); this.area_ref=React.createRef(); } on_change(value) { this.setState({ text: value, }); } on_submit(event) { event.preventDefault(); if(this.state.loading_status==='loading') return; this.setState({ loading_status: 'loading', }); let data=new URLSearchParams(); data.append('action','docomment'); data.append('pid',this.props.pid); data.append('text',this.state.text); data.append('token',this.props.token); fetch(API_BASE+'/api.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: data, }) .then((res)=>res.json()) .then((json)=>{ if(json.code!==0) { if(json.msg) alert(json.msg); throw new Error(json); } this.setState({ loading_status: 'done', text: '', }); this.area_ref.current.clear(); this.props.on_complete(); }) .catch((e)=>{ console.error(e); alert('回复失败\n(树洞服务器经常抽风,其实有可能已经回复上了,不妨点“刷新回复”看一看)'); this.setState({ loading_status: 'done', }); }); } render() { return (
{this.state.loading_status==='loading' ? : } ) } } export class PostForm extends Component { constructor(props) { super(props); this.state={ text: '', loading_status: 'done', }; this.img_ref=React.createRef(); this.area_ref=React.createRef(); this.on_change_bound=this.on_change.bind(this); } on_change(value) { this.setState({ text: value, }); } do_post(text,img) { let data=new URLSearchParams(); data.append('action','dopost'); data.append('text',this.state.text); data.append('type',img ? 'image' : 'text'); data.append('token',this.props.token); if(img) data.append('data',img); fetch(API_BASE+'/api.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: data, }) .then((res)=>res.json()) .then((json)=>{ if(json.code!==0) { if(json.msg) alert(json.msg); throw new Error(json); } this.setState({ loading_status: 'done', text: '', }); this.area_ref.current.clear(); this.props.on_complete(); }) .catch((e)=>{ console.error(e); alert('发表失败'); this.setState({ loading_status: 'done', }); }); } proc_img(file) { // http://pkuhole.chenpong.com/ return new Promise((resolve,reject)=>{ function return_url(url) { const idx=url.indexOf(';base64,'); if(idx===-1) throw new Error('img not base64 encoded'); resolve(url.substr(idx+8)); } let reader=new FileReader(); reader.onload=((event)=>{ // check size const url=event.target.result; const image = new Image(); image.src=url; image.onload=(()=>{ let width=image.width; let height=image.height; if(width>MAX_IMG_PX) { height=height*MAX_IMG_PX/width; width=MAX_IMG_PX; } if(height>MAX_IMG_PX) { width=width*MAX_IMG_PX/height; height=MAX_IMG_PX; } let canvas=document.createElement('canvas'); let ctx=canvas.getContext('2d'); canvas.width=width; canvas.height=height; ctx.drawImage(image,0,0,width,height); for(let quality=.9;quality>0;quality-=0.1) { const url=canvas.toDataURL('image/jpeg',quality); console.log('quality',quality,'size',url.length); if(url.length<=MAX_IMG_FILESIZE) { console.log('chosen img quality',quality); return return_url(url); } } // else alert('图片过大,无法上传'); reject('img too large'); }); }); reader.readAsDataURL(file); }); } on_submit(event) { event.preventDefault(); if(this.state.loading_status==='loading') return; if(this.img_ref.current.files.length) { this.setState({ loading_status: 'processing', }); this.proc_img(this.img_ref.current.files[0]) .then((img)=>{ this.setState({ loading_status: 'loading', }); this.do_post(this.state.text,img); }) } else { this.setState({ loading_status: 'loading', }); this.do_post(this.state.text,null); } } render() { return (
{this.state.loading_status!=='done' ? : }
) } }