use crate::errors::GumError;
use crate::state::{Post, Profile, Reaction, ReactionType, User};
use anchor_lang::prelude::*;
use std::convert::AsRef;
use std::str::FromStr;
use crate::constants::*;
use crate::events::{ReactionDeleted, ReactionNew};
use gpl_session::{session_auth_or, Session, SessionError, SessionToken};
#[derive(Accounts, Session)]
#[instruction(reaction_type: String)]
pub struct CreateReaction<'info> {
#[account(
init,
seeds = [
REACTION_PREFIX_SEED.as_bytes(),
reaction_type.as_bytes(),
to_post.to_account_info().key.as_ref(),
from_profile.to_account_info().key.as_ref(),
],
bump,
payer = authority,
space = Reaction::LEN
)]
pub reaction: Account<'info, Reaction>,
#[account(
seeds = [
POST_PREFIX_SEED.as_bytes(),
to_post.random_hash.as_ref(),
],
bump,
)]
pub to_post: Account<'info, Post>,
#[account(
seeds = [
PROFILE_PREFIX_SEED.as_bytes(),
from_profile.namespace.as_ref().as_bytes(),
user.to_account_info().key.as_ref(),
],
bump,
has_one = user,
)]
pub from_profile: Account<'info, Profile>,
#[account(
seeds = [
USER_PREFIX_SEED.as_bytes(),
user.random_hash.as_ref(),
],
bump,
)]
pub user: Account<'info, User>,
#[session(
signer = authority,
authority = user.authority.key()
)]
pub session_token: Option<Account<'info, SessionToken>>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[session_auth_or(
ctx.accounts.user.authority.key() == ctx.accounts.authority.key(),
GumError::UnauthorizedSigner
)]
pub fn create_reaction_handler(ctx: Context<CreateReaction>, reaction_type: String) -> Result<()> {
let reaction = &mut ctx.accounts.reaction;
reaction.reaction_type = ReactionType::from_str(&reaction_type).unwrap();
reaction.to_post = *ctx.accounts.to_post.to_account_info().key;
reaction.from_profile = *ctx.accounts.from_profile.to_account_info().key;
emit!(ReactionNew {
reaction: *reaction.to_account_info().key,
reaction_type: reaction.reaction_type,
user: *ctx.accounts.user.to_account_info().key,
to_post: *ctx.accounts.to_post.to_account_info().key,
from_profile: *ctx.accounts.from_profile.to_account_info().key,
timestamp: Clock::get()?.unix_timestamp,
});
Ok(())
}
#[derive(Accounts, Session)]
pub struct DeleteReaction<'info> {
#[account(
mut,
seeds = [
REACTION_PREFIX_SEED.as_bytes(),
reaction.reaction_type.as_ref().as_bytes(),
reaction.to_post.as_ref(),
reaction.from_profile.as_ref(),
],
bump,
has_one = to_post,
has_one = from_profile,
close = refund_receiver,
)]
pub reaction: Account<'info, Reaction>,
#[account(
seeds = [
POST_PREFIX_SEED.as_bytes(),
to_post.random_hash.as_ref(),
],
bump,
)]
pub to_post: Account<'info, Post>,
#[account(
seeds = [
PROFILE_PREFIX_SEED.as_bytes(),
from_profile.namespace.as_ref().as_bytes(),
user.to_account_info().key.as_ref(),
],
bump,
has_one = user,
)]
pub from_profile: Account<'info, Profile>,
#[account(
seeds = [
USER_PREFIX_SEED.as_bytes(),
user.random_hash.as_ref(),
],
bump,
)]
pub user: Account<'info, User>,
#[session(
signer = authority,
authority = user.authority.key()
)]
pub session_token: Option<Account<'info, SessionToken>>,
#[account(mut)]
pub authority: Signer<'info>,
#[account(mut, constraint = refund_receiver.key() == user.authority)]
pub refund_receiver: SystemAccount<'info>,
pub system_program: Program<'info, System>,
}
#[session_auth_or(
ctx.accounts.user.authority.key() == ctx.accounts.authority.key(),
GumError::UnauthorizedSigner
)]
pub fn delete_reaction_handler(ctx: Context<DeleteReaction>) -> Result<()> {
emit!(ReactionDeleted {
reaction: *ctx.accounts.reaction.to_account_info().key,
reaction_type: ctx.accounts.reaction.reaction_type,
user: *ctx.accounts.user.to_account_info().key,
to_post: *ctx.accounts.to_post.to_account_info().key,
from_profile: *ctx.accounts.from_profile.to_account_info().key,
timestamp: Clock::get()?.unix_timestamp,
});
Ok(())
}