RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

[RunUO 2.0] Fully Automated Donation Store System

ntony

Sorceror
how am i suppose to add the ipn script to a site or is it written in my paypal already?

To make it clear.
1. You need your Merchant PayPal account ready. Copy the merchant ID.
2. Put the merchant ID to both the .cs config script and .php config script.
3. You need to put .cs scripts on your shard "Script" folder, and the .php scripts to your web server.
 

ntony

Sorceror
For those who have the admin page freezes on "Loading...". Please go to my Google code and download these to latest update on below links. Thanks!

http://code.google.com/p/runuodonat...browse/trunk/donation_store/web/adminpage.php
http://code.google.com/p/runuodonat.../trunk/donation_store/web/get_button_code.php

The reason of occurring this problem is: your PHP server doesn't support short tag.

You may or may not be able to configure the web server option. So, I have put the update to avoid this problem onto Google Code.
 

Vorspire

Knight
BTW ntony, I reviewed your code and it doesn't look very secure, you should consider upgrading your PHP code to PHP 5 standard using classes and keyword modifiers.
 

Nockar

Sorceror
Any idea why I am getting this error? I have not modified the .cs scrips at all other then mysql info.

Code:
Errors:
+ Customs/Donation Store/DonationStore.cs:
    CS0103: Line 60: The name 'ClaimAllDonationItems_OnCommand' does not exist i
n the current context

Code:
using System;
using System.Data;
using System.Data.Odbc;
using System.Net;
using System.Collections;
using System.Xml;
using System.Text;
using System.Reflection;
using Server;
using Server.Misc;
using Server.Network;
using Server.Commands;
namespace Server.Engines.PlayerDonation
{
 //public delegate Item ConstructCallback();
 
 public class DonationStore
 {
  
  private static string
   DatabaseDriver = "{MySQL ODBC 3.51 Driver}",
   DatabaseServer = "aaaa",  // your MySQL database hostname
   DatabaseName = "aaaa",   // the database name of your donation store db
   DatabaseUserID = "aaaa",  // username for your MySQL database access
   DatabasePassword = "aaaa";  // password
  static string ConnectionString = String.Format( "driver={0};server={1};database={2};uid={3};pwd={4}",
   DatabaseDriver, DatabaseServer, DatabaseName, DatabaseUserID, DatabasePassword );
  
  public static void Initialize()
        {
            CommandSystem.Register("claimalldonationitems", AccessLevel.Player, new CommandEventHandler(ClaimAllDonationItems_OnCommand));
        }
  
  public static ArrayList GetDonationGiftList(string username)
  {
   //get a list of item from redeemable_gift table
   ArrayList redeemableGifts = new ArrayList();
   
   IDbConnection connection = null;
   IDbCommand command = null;
   IDataReader reader = null;
   try
   {
    connection = new OdbcConnection( ConnectionString );
    connection.Open( );
    
    
    command = connection.CreateCommand( );
    
    command.CommandText = String.Format("SELECT redeemable_gift.id AS id, redeemable_gift.type_id AS type, gift_type.type_name AS name FROM redeemable_gift INNER JOIN gift_type ON redeemable_gift.type_id=gift_type.type_id WHERE redeemable_gift.account_name='{0}' ORDER BY redeemable_gift.id ASC", username);
    reader = command.ExecuteReader();
    
    while (reader.Read())
    {
     int giftId = System.Convert.ToInt32(reader["id"]);
     int giftTypeId = System.Convert.ToInt32(reader["type"]);
     string giftName = (string)reader["name"];
     DonationGift gift = new DonationGift(giftId, giftTypeId, giftName);
     redeemableGifts.Add(gift);
    }
    reader.Close();
   }
   catch( Exception e )
   {
    Console.WriteLine( "[Retrieve Donation Gift List] Error..." );
    Console.WriteLine( e );
   }
   finally
   {
    if (reader != null && !reader.IsClosed)
     reader.Close();
    if (command != null && connection != null)
    {
     command.Dispose();
     connection.Close();
    }
   }
   
   return redeemableGifts;
  }
  
  public static IEntity RedeemGift(long giftId, string username)
  {
   // move the record from redeenable_gift table to redeemed_gift table
   IDbConnection connection = null;
   IDbCommand command = null;
   IDataReader reader = null;
   
   IEntity gift = null;
   
   try
   {
    connection = new OdbcConnection( ConnectionString );
    connection.Open( );
    command = connection.CreateCommand( );
    
    //get the gift type by selecting redeemable_gift table using id
    command.CommandText = String.Format("SELECT type_id,donate_time,paypal_txn_id FROM redeemable_gift WHERE id='{0}' AND account_name='{1}'", giftId, username);
    reader = command.ExecuteReader();
    
    int typeId;
    int donateTime;
    string paypalTxnId = string.Empty;
    
    if (reader.Read())
    {
     typeId = System.Convert.ToInt32(reader["type_id"]);
     donateTime = System.Convert.ToInt32(reader["donate_time"]);
     paypalTxnId = (string)reader["paypal_txn_id"];
    }
    else
    {
     Console.WriteLine(String.Format("[Redeem Donation Gift] No such Gift(ID:{0}) for Account Name: {1}", giftId, username));
     return null;
    }
    reader.Close();
    command.Dispose();
    
    // insert record to redeemed_gift first
    command = connection.CreateCommand( );
    IDbTransaction transaction = connection.BeginTransaction();
    command.Connection = connection;
    command.Transaction = transaction;
    DateTime currTime = DateTime.Now;
    
    string classConstructString = GetClassNameByType(typeId);
    gift = getGiftInstance(classConstructString);
    if ( gift == null)
    {
     Console.WriteLine(String.Format("[Redeem Donation Gift] Unable to finished the process. Gift(ID:{0}) for Account Name: {1}", giftId, username));
    }
    
    //get the Serial from its instance
    Serial serial = gift.Serial.Value;
    
    //update the serial to database for your later tracking
    command.CommandText = String.Format("INSERT INTO redeemed_gift (id,type_id,account_name,donate_time,redeem_time,serial,paypal_txn_id) VALUES ('{0}','{1}','{2}','{3}','{4}','{5}','{6}')", giftId, typeId, username, donateTime, Convert.ToInt32(ToUnixTimestamp(currTime)), serial.ToString(), paypalTxnId);
    if (command.ExecuteNonQuery() != 1)
    {
     Console.WriteLine(String.Format("[Redeem Donation Gift] (insert record to redeemed_gift) SQL Error. Unable to finished the process. Gift(ID:{0}) for Account Name: {1}", giftId, username));
     transaction.Rollback();
     return null;
    }
    
    //remove record from redeemable_gift
    command.CommandText = String.Format("DELETE FROM redeemable_gift WHERE id='{0}' AND account_name='{1}'", giftId, username);
    
    if (command.ExecuteNonQuery() != 1)
    {
     Console.WriteLine(String.Format("[Redeem Donation Gift] (remove record from redeemable_gift) SQL Error. Unable to finished the process. Gift(ID:{0}) for Account Name: {1}", giftId, username));
     transaction.Rollback();
     return null;
    }
    transaction.Commit();
   }
   catch( Exception e )
   {
    Console.WriteLine( "[Redeem Donation Gift] Error..." );
    Console.WriteLine( e );
   }
   finally
   {
    if (reader != null && !reader.IsClosed)
     reader.Close();
    if (command != null && connection != null)
    {
     command.Dispose();
     connection.Close();
    }
   }
   
   return gift;
  }
  
  public static string GetClassNameByType(int typeId)
  {
   IDbConnection connection = null;
   IDbCommand command = null;
   IDataReader reader = null;
   
   string className = string.Empty;
   
   try
   {
    connection = new OdbcConnection( ConnectionString );
    connection.Open( );
    command = connection.CreateCommand( );
    
    command.CommandText = String.Format("SELECT class_name FROM gift_type WHERE type_id='{0}'", typeId);
    reader = command.ExecuteReader();
    
    
    if (reader.Read())
    {
     className = (string)reader["class_name"];
    }
    else
    {
     Console.WriteLine(String.Format("[Retrieve Donation Gift Class Name] No such gift type: {0}", typeId));
     return null;
    }
    
    
    reader.Close();
    command.Dispose();
    connection.Close();
   }
   catch( Exception e )
   {
    Console.WriteLine( "[Retrieve Donation Gift Class Name] Error..." );
    Console.WriteLine( e );
   }
   finally
   {
    if (reader != null && !reader.IsClosed)
     reader.Close();
    if (command != null && connection != null)
    {
     command.Dispose();
     connection.Close();
    }
   }
   
   return className.Trim();
  }
  
  public static IEntity getGiftInstance(string classConstructString)
  {
   IEntity gift = null;
   //create the object of the gift by its name
   string[] classContructParams = classConstructString.Split(' '); // use space as sperator
   string className = classContructParams[0];
   Type giftType = ScriptCompiler.FindTypeByName( className );
   ConstructorInfo[] ctors = giftType.GetConstructors();
   
   for ( int i = 0; i < ctors.Length; ++i )
   {
    ConstructorInfo ctor = ctors[i];
    if ( !Add.IsConstructable( ctor, AccessLevel.GameMaster ) )
     continue;
    ParameterInfo[] paramList = ctor.GetParameters();
    if ( paramList.Length == (classContructParams.Length - 1) ) // we don't use complex constructors to create the item
    {
     string[] args = new string[classContructParams.Length - 1];
     Array.Copy(classContructParams, 1, args, 0, args.Length);
     object[] param = Add.ParseValues(paramList, args);
     if (param == null)
      continue;
     object giftInstance = ctor.Invoke(param);
     if (giftInstance != null)
     {
      gift = (IEntity)giftInstance;
      break;
     }
     else
      return null;
    }
   }
   
   // get the accessor of this item and check whether it has IsDonation attribute
   PropertyInfo propInfo = giftType.GetProperty("IsDonationItem");
   if ( propInfo != null )
   {
    MethodInfo setterMethod = propInfo.GetSetMethod();
    bool isDonationItem = true;
    object[] parameters = new object[] { isDonationItem };
    setterMethod.Invoke(gift, parameters);
   }
   
   /*
   ConstructCallback cstr = new ConstructCallback( className );
   gift = cstr();
   */
   
   return gift;
  }
  
  static double ToUnixTimestamp( DateTime date )
  {
   DateTime origin = new DateTime( 1970, 1, 1, 0, 0, 0, 0 );
   TimeSpan diff = date - origin;
   
   return Math.Floor( diff.TotalSeconds );
  }

 }
}
 

Nockar

Sorceror
There are 3 .cs files. Thats all the was included in the zip file on the google page. Same for the trunk. Thats all there seems to be?
 

Pure Insanity

Sorceror
Just need to find where the method for this command is.

Code:
[FONT=Consolas]public static void Initialize()        {            CommandSystem.Register("claimalldonationitems", AccessLevel.Player, new CommandEventHandler(ClaimAllDonationItems_OnCommand));        }[/FONT]

It's gotta be there, this thread is rather big for a mistake like that to slip by this long...

Screw it...not gonna bother fixing it, hate how XenFroyo handles code tags... -.-;
 

Nockar

Sorceror
Its weard. There are only 3 .cs scripts. I dont know where the code is at thats missing.

DonationGift.cs
DonationGiftStone.cs
DonationStore.cs
 

Hands Of God

Sorceror
Ah. I assume it opens a gump? Or just gives the item? Calling the same method via command would be easy to do.

This is from the stone

Code:
        public override void OnDoubleClick(Mobile from)
        {
            //check database for this player's account
            Accounting.Account account = from.Account as Accounting.Account;
            string accountName = account.Username;

            from.SendGump( new DonationStoreGump( from ) );
        }
 

Pure Insanity

Sorceror
Then yeah, making a command to do it from anywhere would be rather easy. Kinda silly he started to add support for it...but didn't finish.
 

Vorspire

Knight
This is from the stone

Code:
        public override void OnDoubleClick(Mobile from)
        {
            //check database for this player's account
            Accounting.Account account = from.Account as Accounting.Account;
            string accountName = account.Username;

            from.SendGump( new DonationStoreGump( from ) );
        }

This code it totally unnecessary and has the risk of causing a crash... All you need is:
Code:
if(from != null && !from.Deleted && from is PlayerMobile && from.Account != null)
{ from.SendGump( new DonationStoreGump( from ) ); }

I'm still strongly against anyone actually using this system in a production server, although it is a great attempt to achieve automated payments, it still doesn't meet the standards of security needed in today's greedy society, don't get me wrong though, it's on the right track and has a lot of potential to both fail and succeed :)
Good luck
 

Pure Insanity

Sorceror
Rich (BB code):
if(from != null && !from.Deleted && from is PlayerMobile && !from.Account != null  && !HasGump(typeof(DonationStoreGump)))
{ from.SendGump( new DonationStoreGump( from ) ); }

Refined just a bit more, can never have too many security checks. (This isn't needed if the gump it's self checks for exploits like this, but without a check like this...may be possible to open two of the same gumps and claim the same item twice.) Although I didn't really look at the system to see if this is absolutely needed, but at the same time...idiot checks aren't a bad thing unless it's super resource intensive or something.
 

Vorspire

Knight
Good thing to point out Insanity, but doesn't the HasGump method need a Mobile object reference from which to be called?

I usually use this in the constructors:
Code:
Type gumpType = this.GetType( );

if( user.HasGump( gumpType ) )
{ user.CloseGump( gumpType ); }
So whenever a new gump of it's own type is created, it closes the old one regardless.
 

Pure Insanity

Sorceror
I do the same thing for my gumps too, unless I want to prevent them from opening the same gump twice (resending different data) it really depends on the gump type. But yes, you are correct. I didn't stop to think this code was being called form something inheriting the Item class. Instead it should be.

Code:
!from.HasGump(typeof(DonationStoreGump))

Still an easy enough fix. =P

A system like this, should be very secure. It's not something you wanna take chances at, as this is a system that people would indeed try and exploit. =P
 

Pure Insanity

Sorceror
And your constructor code could be shortened a line too. =P

Code:
if( user.HasGump(this.GetType()) )
{ user.CloseGump(this.GetType()); }

There is no need to store the type in it's own variable as very few gumps would ever need that bit of code again. But at the same time...depends on the programmer and how they like to read their own code.
 
Top