sugoi internally added

This commit is contained in:
pvincent
2021-08-27 17:54:17 +04:00
parent ef31c26525
commit 445448f43b
100 changed files with 8758 additions and 23 deletions
+132
View File
@@ -0,0 +1,132 @@
package sugoi.db;
import sys.db.Types;
import sugoi.mail.IMail;
import sugoi.mail.IMailer;
/**
* DB Buffer for emails
*/
@:index(remoteId,sdate,cdate)
class BufferedMail extends sys.db.Object
{
public var id : SId;
//email content
public var title : SString<256>;
public var htmlBody : SNull<SText>;
public var textBody : SNull<SText>;
public var headers : SData<Map<String,String>>;
public var sender : SData<{name:String,email:String,?userId:Int}>;
public var recipients : SData<Array<{name:String,email:String,?userId:Int}>>;
//utility fields
public var mailerType : SString<32>; //mailer used when sending for real
public var tries : SInt; //number of times we tried to send the mail
public var cdate : SDateTime; //creation date
public var sdate : SNull<SDateTime>; //sent date
public var rawStatus : SNull<SText>; //raw return from the smtp server or mandrill API
public var status : SNull<SData<MailerResult>>; //map of emails with api/smtp results
//custom datas
public var data : SNull<SData<Dynamic>>;//custom datas
public var remoteId : SNull<Int>; //custom remote Id (userId, groupId ...)
public function getMailerResultMessage(k:String):{failure:String, success:String}{
var t = sugoi.i18n.Locale.texts;
var out = {failure:null, success:null};
switch(status.get(k)){
case tink.core.Outcome.Failure(f):
out.failure = switch(f){
case GenericError(e): t._("Generic error: ") + e.toString();
case HardBounce : t._("Mailbox does not exist");
case SoftBounce : t._("Mailbox full or blocked");
case Spam: t._("Message considered as spam");
case Unsub: t._("This user unsubscribed");
case Unsigned: t._("Sender incorrect (Unsigned)");
};
case tink.core.Outcome.Success(s):
out.success = switch(s){
case Sent : t._("Sent");
case Queued : t._("Queued");
};
}
return out;
}
public function new(){
super();
cdate = Date.now();
tries = 0;
}
public function isSent(){
return sdate!=null;
}
/**
* Finally really send the message
*/
public function finallySend():Void{
if(isSent()) throw "already sent";
var conf = {
smtp_host:sugoi.db.Variable.get("smtp_host"),
smtp_port:sugoi.db.Variable.getInt("smtp_port"),
smtp_user:sugoi.db.Variable.get("smtp_user"),
smtp_pass:sugoi.db.Variable.get("smtp_pass")
};
var mailer : sugoi.mail.IMailer = switch(this.mailerType){
case "mandrill":
new sugoi.mail.MandrillMailer().init(conf);
case "smtp":
new sugoi.mail.SmtpMailer().init(conf);
case "debug":
new sugoi.mail.DebugMailer();
default :
throw "Unknown mailer type : "+this.mailerType;
};
var m = new sugoi.mail.Mail();
for( k in this.headers.keys() ) m.setHeader( k,headers[k] );
m.setSubject(this.title);
for( r in recipients) m.setRecipient(r.email,r.name,r.userId);
m.setSender(sender.email,sender.name,sender.userId);
m.setHtmlBody(this.htmlBody);
m.setTextBody(this.textBody);
this.lock();
this.tries++;
try{
mailer.send(m,null,afterSendCb);
this.sdate = Date.now();
this.rawStatus = null;
}catch(e:Dynamic){
this.sdate = null;
this.rawStatus = Std.string(e);
// App.current.logError( Std.string(e) );
}
this.update();
}
function afterSendCb(status:MailerResult){
//App.current.logError(status);
this.status = status;
this.update();
}
}
+65
View File
@@ -0,0 +1,65 @@
package sugoi.db;
import sys.db.Types;
/**
* Key-Value temporary storage in a Memcached style
*/
@:id(name)
class Cache extends sys.db.Object
{
public var name : SString<128>;
public var value : SText;
public var expire : SDateTime;
public var cdate : SNull<SDateTime>;
public function new(){
super();
cdate = Date.now();
}
/**
* Read the value for key $id
*/
public static function get(id:String):Dynamic {
if (Std.random(1000) == 0) Cache.manager.delete($expire < Date.now());
var c = manager.get(id, true);
if (c == null) return null;
if (c.expire.getTime() < Date.now().getTime()) {
c.delete();
return null;
}
return haxe.Unserializer.run(c.value);
}
/**
* Set a value for key $id
* and optionnaly a lifetime in seconds
*/
public static function set(id:String, value:Dynamic,expireInSeconds:Float) {
var c = manager.get(id, true);
var niou = false;
if (c == null) {
niou = true;
c = new Cache();
c.name = id;
}
c.value = haxe.Serializer.run(value);
c.expire = DateTools.delta(Date.now(), expireInSeconds*1000.0);
if (niou) {
c.insert();
}else {
c.update();
}
}
/**
* Delete a value for key $id
*/
public static function destroy(id:String) {
var c = manager.get(id, true);
if (c != null) c.delete();
}
}
+16
View File
@@ -0,0 +1,16 @@
package sugoi.db;
import sys.db.Types;
class Error extends sys.db.Object {
public var id : SId;
public var date : SDateTime;
public var error : SText;
@:relation(uid) public var user : SNull<db.User>;
public var ip : SNull<SString<15>>;
public var userAgent : SNull<SString<256>>;
public var url : SNull<STinyText>;
}
+77
View File
@@ -0,0 +1,77 @@
package sugoi.db;
import sys.db.Manager;
import sys.db.Types;
/**
* Store files in DB
*/
class File extends sys.db.Object {
public var id : SId;
public var name : STinyText; //filename
public var cdate : SNull<SDateTime>; //creation datetime
public var data : SBinary;
@:skip
static var CACHE = [];
override public function new(){
super();
cdate = Date.now();
}
/**
* Get the file name related to this File record.
* Usually files should be generated in /file/
*/
public static function makeSign( id : Int ) {
if( id == null )
return "";
var s = CACHE[id];
if( s != null ) return s;
s = id+"_"+haxe.crypto.Md5.encode(id + App.config.get('key'));
CACHE[id] = s;
return s;
}
public override function toString() {
return "#" + id + " " + name;
}
/**
* Creates a File record
* from string data (typically sent from a form) and a file name
*/
public static function create(stringData:String, ?fileName=""):File {
var bytes = new haxe.io.StringInput(stringData).readAll();
return createFromBytes(bytes, fileName);
}
public static function createFromBytes(b:haxe.io.Bytes, ?fileName=""):File {
#if neko
var f = new File();
f.name = fileName;
f.data = b;
f.insert();
return f;
#else
//there is a bug in PHP, we do it manually
var hexa = b.toHex();
Manager.cnx.request("INSERT INTO File (name,data) VALUES ('"+fileName+"', 0x"+hexa+")");
return File.manager.select($name==fileName);
#end
}
public function getExtension():String {
if (name == null || name=="") return "jpg";
return name.split(".")[1];
}
}
+135
View File
@@ -0,0 +1,135 @@
package sugoi.db;
import sys.db.Types;
import db.User;
#if neko
import neko.Web;
#else
import php.Web;
#end
@:id(sid)
@:index(uid,unique)
class Session extends sys.db.Object {
public var sid : SString<32>;
public var ip : SString<15>;
public var lang : SString<2>;
public var messages : SData<Array<{ error : Bool, text : String }>>;
public var lastTime : SDateTime;
public var createTime : SDateTime;
#if neko
public var sdata : SNekoSerialized;
#else
public var sdata : SText;
#end
@:skip public var data : Dynamic;
//public var uid : SNull<SInt>;
@:relation(uid) public var user : SNull<db.User>;
public function new() {
super();
messages = [];
data = {};
}
/**
* Stores a message in session
*/
public function addMessage( text : String, ?error=false ) {
messages.push({ error : error, text : text });
}
public function setUser( u : User ):Void {
//remove any previous session for this user
manager.delete($uid==u.id);
lang = u.lang;
user = u;
update();
App.current.user = u;
}
public override function update() {
#if neko
sdata = neko.Lib.serialize(data);
#else
sdata = haxe.Serializer.run(data);
#end
lastTime = Date.now();
super.update();
}
private static function get( sid:String ):Session {
if ( sid == null ) return null;
var s = manager.get(sid,true);
if ( s == null ) return null;
try {
#if neko
s.data = neko.Lib.localUnserialize(s.sdata);
#else
s.data = haxe.Unserializer.run(s.sdata);
#end
}catch (e:Dynamic) {
s.data = null;
}
return s;
}
public static function init( sids : Array<String> ) {
for( sid in sids ) {
var s = get(sid);
if( s != null ) return s;
}
var ip = Web.getClientIP();
var s = new Session();
s.ip = ip;
s.createTime = Date.now();
s.lastTime = Date.now();
s.sid = generateId();
var count = 20;
while( try { s.insert(); false; } catch( e : Dynamic ) true ) {
s.sid = generateId();
// prevent infinite loop in SQL error
if( count-- == 0 ) {
s.insert();
break;
}
}
return s;
}
/**
* Generate a random 32 chars string
*/
public static var S = "abcdefjhijklmnopqrstuvwxyABCDEFJHIJKLMNOPQRSTUVWXYZ0123456789";
public static function generateId():String {
var id = "";
for ( x in 0...32 ) {
id += S.substr(Std.random(S.length),1);
}
return id;
}
/**
* Delete sessions older than 1 month
*/
public static function clean() {
manager.delete($lastTime < DateTools.delta(Date.now(),-1000.0*60*60*24*30));
}
}
+48
View File
@@ -0,0 +1,48 @@
package sugoi.db;
import sys.db.Types;
@:id(name)
class Variable extends sys.db.Object {
public var name : SString<50>;
public var value : SString<50>;
public static function get( name ) {
var v = manager.get(name,false);
return v == null ? null : v.value;
}
public static function set(name, val:Dynamic) {
var v = Variable.manager.get(name,true);
if (v==null) {
v = new Variable();
v.name = name;
v.value = Std.string(val);
v.insert();
}
else {
v.value = Std.string(val);
v.update();
}
}
public static function increment(name, ?inc=1) {
var v = Variable.manager.get(name,true);
if (v==null) {
v = new Variable();
v.name = name;
v.value = Std.string(inc);
v.insert();
}
else {
v.value = Std.string(Std.parseInt(v.value)+1);
v.update();
}
}
public static function getInt( name ) {
var v = manager.get(name,false);
return v == null ? 0 : Std.parseInt(v.value);
}
}