email state

This commit is contained in:
ntr 2019-08-26 19:09:49 +10:00
parent 1e96a8ee5a
commit 2da5684156
9 changed files with 65 additions and 13 deletions

View File

@ -16,6 +16,7 @@ export const setConstructs = value => ({ type: 'SET_CONSTRUCTS', value });
export const setConstructRename = value => ({ type: 'SET_CONSTRUCT_RENAME', value }); export const setConstructRename = value => ({ type: 'SET_CONSTRUCT_RENAME', value });
export const setGame = value => ({ type: 'SET_GAME', value }); export const setGame = value => ({ type: 'SET_GAME', value });
export const setInfo = value => ({ type: 'SET_INFO', value }); export const setInfo = value => ({ type: 'SET_INFO', value });
export const setEmail = value => ({ type: 'SET_EMAIL', value });
export const setInstance = value => ({ type: 'SET_INSTANCE', value }); export const setInstance = value => ({ type: 'SET_INSTANCE', value });
export const setInstances = value => ({ type: 'SET_INSTANCES', value }); export const setInstances = value => ({ type: 'SET_INSTANCES', value });
export const setItemEquip = value => ({ type: 'SET_ITEM_EQUIP', value }); export const setItemEquip = value => ({ type: 'SET_ITEM_EQUIP', value });

View File

@ -12,6 +12,7 @@ const addState = connect(
function receiveState(state) { function receiveState(state) {
const { const {
account, account,
email,
ping, ping,
ws, ws,
} = state; } = state;
@ -51,6 +52,7 @@ const addState = connect(
return { return {
account, account,
ping, ping,
email,
logout, logout,
setPassword, setPassword,
setEmail, setEmail,
@ -74,6 +76,7 @@ class AccountStatus extends Component {
const { const {
account, account,
ping, ping,
email,
logout, logout,
setPassword, setPassword,
setEmail, setEmail,
@ -105,9 +108,9 @@ class AccountStatus extends Component {
<label for="email">Email Settings:</label> <label for="email">Email Settings:</label>
<dl> <dl>
<dt>Recovery Email</dt> <dt>Recovery Email</dt>
<dd>{account.email ? account.email : 'No email set'}</dd> <dd>{email ? email.email : 'No email set'}</dd>
<dt>Status</dt> <dt>Status</dt>
<dd>{account.email_confirmed ? 'Confirmed' : 'Unconfirmed'}</dd> <dd>{email && email.confirmed ? 'Confirmed' : 'Unconfirmed'}</dd>
</dl> </dl>
<input <input
class="login-input" class="login-input"

View File

@ -101,6 +101,10 @@ function registerEvents(store) {
store.dispatch(actions.setAccount(account)); store.dispatch(actions.setAccount(account));
} }
function setEmail(email) {
store.dispatch(actions.setEmail(email));
}
function setShop(v) { function setShop(v) {
store.dispatch(actions.setShop(v)); store.dispatch(actions.setShop(v));
} }
@ -212,6 +216,7 @@ function registerEvents(store) {
setConstructList, setConstructList,
setNewConstruct, setNewConstruct,
setGame, setGame,
setEmail,
setInstance, setInstance,
setItemInfo, setItemInfo,
setPing, setPing,

View File

@ -28,6 +28,7 @@ module.exports = {
constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'), constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'),
constructRename: createReducer(null, 'SET_CONSTRUCT_RENAME'), constructRename: createReducer(null, 'SET_CONSTRUCT_RENAME'),
game: createReducer(null, 'SET_GAME'), game: createReducer(null, 'SET_GAME'),
email: createReducer(null, 'SET_EMAIL'),
info: createReducer(null, 'SET_INFO'), info: createReducer(null, 'SET_INFO'),
instance: createReducer(null, 'SET_INSTANCE'), instance: createReducer(null, 'SET_INSTANCE'),
instances: createReducer([], 'SET_INSTANCES'), instances: createReducer([], 'SET_INSTANCES'),

View File

@ -150,6 +150,10 @@ function createSocket(events) {
events.setShop(shop); events.setShop(shop);
} }
function onEmailState(v) {
events.setEmail(v);
}
function onAccountInstances(list) { function onAccountInstances(list) {
events.setAccountInstances(list); events.setAccountInstances(list);
} }
@ -198,6 +202,7 @@ function createSocket(events) {
AccountShop: onAccountShop, AccountShop: onAccountShop,
ConstructSpawn: onConstructSpawn, ConstructSpawn: onConstructSpawn,
GameState: onGameState, GameState: onGameState,
EmailState: onEmailState,
InstanceState: onInstanceState, InstanceState: onInstanceState,
ItemInfo: onItemInfo, ItemInfo: onItemInfo,
Pong: onPong, Pong: onPong,

5
etc/mnml/gs.SAMPLE.conf Normal file
View File

@ -0,0 +1,5 @@
DATABASE_URL=postgres://mnml:password@somewhere/mnml
MAIL_ADDRESS=machines@mnml.gg
MAIL_DOMAIN=vinyl.mnml.gg
MAIL_PASSWORD=mmmmmmmmmmmmmmmm

View File

@ -1 +0,0 @@
DATABASE_URL=postgres://mnml:password@somewhere/mnml

View File

@ -16,13 +16,13 @@ use lettre::smtp::error::Error as MailError;
use lettre::smtp::extension::ClientId; use lettre::smtp::extension::ClientId;
use lettre::smtp::response::Response; use lettre::smtp::response::Response;
use lettre::{SendableEmail, SmtpClient, SmtpTransport, Transport}; use lettre::{SendableEmail, SmtpClient, SmtpTransport, Transport};
use lettre_email::Email; use lettre_email::Email as LettreEmail;
use account::Account; use account::Account;
use pg::Db; use pg::Db;
#[derive(Debug)] #[derive(Debug,Clone,Serialize)]
pub struct UserEmail { pub struct Email {
pub id: Uuid, pub id: Uuid,
pub email: String, pub email: String,
pub account: Uuid, pub account: Uuid,
@ -50,7 +50,7 @@ http://mnml.gg/api/account/recover?recover_token={:}
glhf glhf
--mnml", name, token); --mnml", name, token);
Email::builder() LettreEmail::builder()
.from("machines@mnml.gg") .from("machines@mnml.gg")
.to(email.clone()) .to(email.clone())
.subject("account recovery") .subject("account recovery")
@ -68,7 +68,7 @@ http://mnml.gg/api/account/email/confirm?confirm_token={:}
glhf glhf
--mnml", name, token); --mnml", name, token);
Email::builder() LettreEmail::builder()
.from("machines@mnml.gg") .from("machines@mnml.gg")
.to(email.clone()) .to(email.clone())
.subject("email confirmation") .subject("email confirmation")
@ -109,7 +109,7 @@ pub fn confirm_email(tx: &mut Transaction, account: &Account, confirm_token: Str
return Ok((email, account)); return Ok((email, account));
} }
pub fn select(db: &Db, email: &String) -> Result<UserEmail, Error> { pub fn select(db: &Db, email: &String) -> Result<Email, Error> {
let query = " let query = "
SELECT id, email, account, confirmed SELECT id, email, account, confirmed
FROM emails FROM emails
@ -127,7 +127,28 @@ pub fn select(db: &Db, email: &String) -> Result<UserEmail, Error> {
let account: Uuid = row.get(2); let account: Uuid = row.get(2);
let confirmed: bool = row.get(3); let confirmed: bool = row.get(3);
return Ok(UserEmail { id, email, account, confirmed }); return Ok(Email { id, email, account, confirmed });
}
pub fn select_account(db: &Db, account: Uuid) -> Result<Email, Error> {
let query = "
SELECT id, email, account, confirmed
FROM emails
WHERE account = $1;
";
let result = db
.query(query, &[&account])?;
let row = result.iter().next()
.ok_or(err_msg("email found"))?;
let id: Uuid = row.get(0);
let email: String = row.get(1);
let account: Uuid = row.get(2);
let confirmed: bool = row.get(3);
return Ok(Email { id, email, account, confirmed });
} }
pub fn set_recovery(tx: &mut Transaction, email: &String) -> Result<String, Error> { pub fn set_recovery(tx: &mut Transaction, email: &String) -> Result<String, Error> {
@ -158,7 +179,7 @@ pub fn set_recovery(tx: &mut Transaction, email: &String) -> Result<String, Erro
return Ok(recover_token); return Ok(recover_token);
} }
pub fn get_recovery(tx: &mut Transaction, recover_token: &String) -> Result<UserEmail, Error> { pub fn get_recovery(tx: &mut Transaction, recover_token: &String) -> Result<Email, Error> {
// set a new token when recovering to prevent multiple access // set a new token when recovering to prevent multiple access
let mut rng = thread_rng(); let mut rng = thread_rng();
let new_token: String = iter::repeat(()) let new_token: String = iter::repeat(())
@ -186,7 +207,7 @@ pub fn get_recovery(tx: &mut Transaction, recover_token: &String) -> Result<User
let account: Uuid = row.get(2); let account: Uuid = row.get(2);
let confirmed: bool = row.get(3); let confirmed: bool = row.get(3);
return Ok(UserEmail { id, email, account, confirmed }); return Ok(Email { id, email, account, confirmed });
} }
pub fn set(tx: &mut Transaction, account: Uuid, email: &String) -> Result<(Uuid, String), Error> { pub fn set(tx: &mut Transaction, account: Uuid, email: &String) -> Result<(Uuid, String), Error> {

View File

@ -22,13 +22,15 @@ use game::{Game, game_state, game_skill, game_ready};
use instance::{Instance, instance_state, instance_practice, instance_ready}; use instance::{Instance, instance_state, instance_practice, instance_ready};
use item::{Item, ItemInfoCtr, item_info}; use item::{Item, ItemInfoCtr, item_info};
use mtx; use mtx;
use mail;
use mail::Email;
use pg::{Db}; use pg::{Db};
use pg::{PgPool}; use pg::{PgPool};
use skill::{Skill, dev_resolve, Resolutions}; use skill::{Skill, dev_resolve, Resolutions};
use vbox::{vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip}; use vbox::{vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip};
use http::{AUTH_CLEAR, TOKEN_HEADER}; use http::{AUTH_CLEAR, TOKEN_HEADER};
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize)]
pub enum RpcMessage { pub enum RpcMessage {
AccountState(Account), AccountState(Account),
AccountConstructs(Vec<Construct>), AccountConstructs(Vec<Construct>),
@ -36,6 +38,7 @@ pub enum RpcMessage {
AccountInstances(Vec<Instance>), AccountInstances(Vec<Instance>),
AccountShop(mtx::Shop), AccountShop(mtx::Shop),
ConstructSpawn(Construct), ConstructSpawn(Construct),
EmailState(Email),
GameState(Game), GameState(Game),
ItemInfo(ItemInfoCtr), ItemInfo(ItemInfoCtr),
@ -225,6 +228,15 @@ impl Handler for Connection {
let db = self.pool.get().unwrap(); let db = self.pool.get().unwrap();
let mut tx = db.transaction().unwrap(); let mut tx = db.transaction().unwrap();
// email state
match mail::select_account(&db, a.id) {
Ok(e) => {
self.ws.send(RpcMessage::EmailState(e.clone())).unwrap();
self.events.send(Event::Subscribe(self.id, e.id)).unwrap();
},
Err(_) => (),
};
// send account constructs // send account constructs
let account_constructs = account::constructs(&mut tx, a).unwrap(); let account_constructs = account::constructs(&mut tx, a).unwrap();
self.ws.send(RpcMessage::AccountConstructs(account_constructs)).unwrap(); self.ws.send(RpcMessage::AccountConstructs(account_constructs)).unwrap();