Reorder functions, no functional changes

This commit is contained in:
Deon George 2024-05-09 21:31:50 +10:00
parent 23159d19d5
commit edee0643ec
3 changed files with 276 additions and 279 deletions
app
Http/Controllers
Models
Notifications/Netmails

View File

@ -50,7 +50,7 @@ class UserController extends Controller
]); ]);
$ao = Address::findOrFail($request->address_id); $ao = Address::findOrFail($request->address_id);
if ($ao->check_activation(Auth::user(),$request->code)) { if ($ao->activation_check(Auth::user(),$request->code)) {
$ao->validated = TRUE; $ao->validated = TRUE;
$ao->save(); $ao->save();

View File

@ -77,6 +77,244 @@ class Address extends Model
}); });
} }
/**
* Create an FTN address associated with a system
*
* @param string $address
* @param System $so
* @return Address|null
* @throws \Exception
*/
public static function createFTN(string $address,System $so): ?self
{
$ftn = self::parseFTN($address);
if (! $ftn['d']) {
// See if we have a default domain for this domain
if ($ftn['z']) {
$zo = Zone::where('zone_id',$ftn['z'])->where('default',TRUE)->single();
if ($zo)
$ftn['d'] = $zo->domain->name;
else {
Log::alert(sprintf('%s:! Refusing to create address [%s] no domain available',self::LOGKEY,$address));
return NULL;
}
}
}
Log::debug(sprintf('%s:- Creating AKA [%s] for [%s]',self::LOGKEY,$address,$so->name));
// Check Domain exists
Domain::unguard();
$do = Domain::singleOrNew(['name'=>$ftn['d']]);
Domain::reguard();
if (! $do->exists) {
$do->public = TRUE;
$do->active = TRUE;
$do->notes = 'Auto created';
$do->save();
}
// If the zone is zero, see if this is a flatten domain, and if so, find an NC
if (($ftn['z'] === 0) && $do->flatten) {
$nc = self::findZone($do,$ftn['n'],0,0);
if ($nc) {
Log::info(sprintf('%s:- Setting zone to [%d]',self::LOGKEY,$nc->zone->zone_id));
$ftn['z'] = $nc->zone->zone_id;
}
}
// Create zone
Zone::unguard();
$zo = Zone::singleOrNew(['domain_id'=>$do->id,'zone_id'=>$ftn['z']]);
Zone::reguard();
if (! $zo->exists) {
$zo->active = TRUE;
$zo->notes = 'Auto created';
$zo->system_id = System::createUnknownSystem()->id;
$do->zones()->save($zo);
}
if (! $zo->active || ! $do->active) {
Log::alert(sprintf('%s:! Refusing to create address [%s] in disabled zone or domain',self::LOGKEY,$address));
return NULL;
}
// Create Address, assigned to $so
$o = new self;
$o->active = TRUE;
$o->zone_id = $zo->id;
$o->region_id = 0; // @todo Automatically determine region
$o->host_id = $ftn['n'];
$o->node_id = $ftn['f'];
$o->point_id = $ftn['p'];
try {
$so->addresses()->save($o);
} catch (QueryException $e) {
Log::error(sprintf('%s:! ERROR creating address [%s] (%s)',self::LOGKEY,$o->ftn,get_class($e)));
return NULL;
}
return $o;
}
/**
* Find a record in the DB for a node string, eg: 10:1/1.0
*
* @param string $address
* @param bool $trashed
* @return Address|null
* @throws \Exception
*/
public static function findFTN(string $address,bool $trashed=FALSE): ?self
{
$ftn = self::parseFTN($address);
$o = NULL;
$query = (new self)
->select('addresses.*')
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->when($trashed,function($query) {
$query->withTrashed();
},function($query) {
$query->active();
})
->where('zones.zone_id',$ftn['z'])
->where('node_id',$ftn['f'])
->where('point_id',$ftn['p'])
->when($ftn['d'],function($query,$domain) {
$query->where('domains.name',$domain);
},function($query) {
$query->where('zones.default',TRUE);
})
->orderBy('created_at','DESC');
$q = $query->clone();
// Are we looking for a region address
if (($ftn['f'] === 0) && ($ftn['p'] === 0))
$o = $query
->where('region_id',$ftn['n'])
->where('host_id',$ftn['n'])
->first();
// Look for a normal address
if (! $o)
$o = $q
->where(function($q) use ($ftn) {
return $q
->where(function($q) use ($ftn) {
return $q
->where('region_id',$ftn['n'])
->where('host_id',$ftn['n']);
})
->orWhere('host_id',$ftn['n']);
})
->first();
// Check and see if we are a flattened domain, our address might be available with a different zone.
// This occurs when we are parsing 2D addresses from SEEN-BY, but we have the zone
if (! $o && ($ftn['p'] === 0)) {
if ($ftn['d'])
$do = Domain::where(['name'=>$ftn['d']])->single();
else {
$zo = Zone::where('zone_id',$ftn['z'])->where('default',TRUE)->single();
$do = $zo?->domain;
}
if ($do && $do->flatten && (($ftn['z'] === 0) || $do->zones->pluck('zone_id')->contains($ftn['z'])))
$o = self::findZone($do,$ftn['n'],$ftn['f'],$ftn['p'],$trashed);
}
return ($o && $o->system->active) ? $o : NULL;
}
/**
* This is to find an address for a domain (like fidonet), which is technically 2D even though it uses multiple zones.
*
* This was implemented to identify seenby and path kludges
*
* @param Domain $do
* @param int $host
* @param int $node
* @param int $point
* @param bool $trashed
* @return self|null
* @throws \Exception
*/
public static function findZone(Domain $do,int $host,int $node,int $point,bool $trashed=FALSE): ?self
{
if (! $do->flatten)
throw new \Exception(sprintf('Domain is not set with flatten: %d',$do->id));
$zones = $do->zones->pluck('zone_id');
$o = (new self)
->select('addresses.*')
->join('zones',['zones.id'=>'addresses.zone_id'])
->when($trashed,function($query) {
$query->withTrashed();
},function($query) {
$query->active();
})
->whereIN('zones.zone_id',$zones)
->where(function($q) use ($host) {
return $q
->where(function($q) use ($host) {
return $q->where('region_id',$host)
->where('host_id',$host);
})
->orWhere('host_id',$host);
})
->where('node_id',$node)
->where('point_id',$point)
->where('zones.domain_id',$do->id)
->single();
return $o;
}
/**
* Parse a string and split it out as an FTN array
*
* @param string $ftn
* @return array
* @throws \Exception
*/
public static function parseFTN(string $ftn): array
{
if (! preg_match(sprintf('#^%s$#',self::ftn_regex),strtolower($ftn),$matches))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - regex failed',serialize($ftn)));
// Check our numbers are correct.
foreach ([1,2,3] as $i)
if ((! is_numeric($matches[$i])) || ($matches[$i] > self::ADDRESS_FIELD_MAX))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - zone, host, or node address invalid [%d]',$ftn,$matches[$i]));
if ((! empty($matches[4])) AND ((! is_numeric($matches[$i])) || ($matches[4] > self::ADDRESS_FIELD_MAX)))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4]));
return [
'z'=>(int)$matches[1],
'n'=>(int)$matches[2],
'f'=>(int)$matches[3],
'p'=>empty($matches[4]) ? 0 : (int)$matches[4],
'd'=>$matches[5] ?? NULL
];
}
/* SCOPES */ /* SCOPES */
/** /**
@ -516,6 +754,41 @@ class Address extends Model
/* METHODS */ /* METHODS */
/**
* Check the user's activation code for this address is correct
*
* @param User $uo
* @param string $code
* @return bool
*/
public function activation_check(User $uo,string $code): bool
{
try {
Log::info(sprintf('%s:Checking Activation code [%s] is valid for user [%d]',self::LOGKEY,$code,$uo->id));
return ($code === $this->activation_set($uo));
} catch (\Exception $e) {
Log::error(sprintf('%s:! Activation code [%s] invalid for user [%d]',self::LOGKEY,$code,$uo->id));
return FALSE;
}
}
/**
* Create an activation code for this address
*
* @param User $uo
* @return string
*/
public function activation_set(User $uo): string
{
return sprintf('%x:%s',
$this->id,
substr(md5(sprintf('%d:%x',$uo->id,timew($this->updated_at))),0,10)
);
}
/** /**
* Find the immediate children dependent on this record * Find the immediate children dependent on this record
* *
@ -600,253 +873,6 @@ class Address extends Model
return $children->filter(function($item) use ($exclude) { return ! $exclude->pluck('id')->contains($item->id);}); return $children->filter(function($item) use ($exclude) { return ! $exclude->pluck('id')->contains($item->id);});
} }
/**
* Create an FTN address associated with a system
*
* @param string $address
* @param System $so
* @return Address|null
* @throws \Exception
* @todo Move to Static
*/
public static function createFTN(string $address,System $so): ?self
{
$ftn = self::parseFTN($address);
if (! $ftn['d']) {
// See if we have a default domain for this domain
if ($ftn['z']) {
$zo = Zone::where('zone_id',$ftn['z'])->where('default',TRUE)->single();
if ($zo)
$ftn['d'] = $zo->domain->name;
else {
Log::alert(sprintf('%s:! Refusing to create address [%s] no domain available',self::LOGKEY,$address));
return NULL;
}
}
}
Log::debug(sprintf('%s:- Creating AKA [%s] for [%s]',self::LOGKEY,$address,$so->name));
// Check Domain exists
Domain::unguard();
$do = Domain::singleOrNew(['name'=>$ftn['d']]);
Domain::reguard();
if (! $do->exists) {
$do->public = TRUE;
$do->active = TRUE;
$do->notes = 'Auto created';
$do->save();
}
// If the zone is zero, see if this is a flatten domain, and if so, find an NC
if (($ftn['z'] === 0) && $do->flatten) {
$nc = self::findZone($do,$ftn['n'],0,0);
if ($nc) {
Log::info(sprintf('%s:- Setting zone to [%d]',self::LOGKEY,$nc->zone->zone_id));
$ftn['z'] = $nc->zone->zone_id;
}
}
// Create zone
Zone::unguard();
$zo = Zone::singleOrNew(['domain_id'=>$do->id,'zone_id'=>$ftn['z']]);
Zone::reguard();
if (! $zo->exists) {
$zo->active = TRUE;
$zo->notes = 'Auto created';
$zo->system_id = System::createUnknownSystem()->id;
$do->zones()->save($zo);
}
if (! $zo->active || ! $do->active) {
Log::alert(sprintf('%s:! Refusing to create address [%s] in disabled zone or domain',self::LOGKEY,$address));
return NULL;
}
// Create Address, assigned to $so
$o = new self;
$o->active = TRUE;
$o->zone_id = $zo->id;
$o->region_id = 0; // @todo Automatically determine region
$o->host_id = $ftn['n'];
$o->node_id = $ftn['f'];
$o->point_id = $ftn['p'];
try {
$so->addresses()->save($o);
} catch (QueryException $e) {
Log::error(sprintf('%s:! ERROR creating address [%s] (%s)',self::LOGKEY,$o->ftn,get_class($e)));
return NULL;
}
return $o;
}
/**
* Find a record in the DB for a node string, eg: 10:1/1.0
*
* @param string $address
* @param bool $trashed
* @return Address|null
* @throws \Exception
* @todo Move to Static
*/
public static function findFTN(string $address,bool $trashed=FALSE): ?self
{
$ftn = self::parseFTN($address);
$o = NULL;
$query = (new self)
->select('addresses.*')
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->when($trashed,function($query) {
$query->withTrashed();
},function($query) {
$query->active();
})
->where('zones.zone_id',$ftn['z'])
->where('node_id',$ftn['f'])
->where('point_id',$ftn['p'])
->when($ftn['d'],function($query,$domain) {
$query->where('domains.name',$domain);
},function($query) {
$query->where('zones.default',TRUE);
})
->orderBy('created_at','DESC');
$q = $query->clone();
// Are we looking for a region address
if (($ftn['f'] === 0) && ($ftn['p'] === 0))
$o = $query
->where('region_id',$ftn['n'])
->where('host_id',$ftn['n'])
->first();
// Look for a normal address
if (! $o)
$o = $q
->where(function($q) use ($ftn) {
return $q
->where(function($q) use ($ftn) {
return $q
->where('region_id',$ftn['n'])
->where('host_id',$ftn['n']);
})
->orWhere('host_id',$ftn['n']);
})
->first();
// Check and see if we are a flattened domain, our address might be available with a different zone.
// This occurs when we are parsing 2D addresses from SEEN-BY, but we have the zone
if (! $o && ($ftn['p'] === 0)) {
if ($ftn['d'])
$do = Domain::where(['name'=>$ftn['d']])->single();
else {
$zo = Zone::where('zone_id',$ftn['z'])->where('default',TRUE)->single();
$do = $zo?->domain;
}
if ($do && $do->flatten && (($ftn['z'] === 0) || $do->zones->pluck('zone_id')->contains($ftn['z'])))
$o = self::findZone($do,$ftn['n'],$ftn['f'],$ftn['p'],$trashed);
}
return ($o && $o->system->active) ? $o : NULL;
}
/**
* This is to find an address for a domain (like fidonet), which is technically 2D even though it uses multiple zones.
*
* This was implemented to identify seenby and path kludges
*
* @param Domain $do
* @param int $host
* @param int $node
* @param int $point
* @param bool $trashed
* @return self|null
* @throws \Exception
* @todo Move to Static
*/
public static function findZone(Domain $do,int $host,int $node,int $point,bool $trashed=FALSE): ?self
{
if (! $do->flatten)
throw new \Exception(sprintf('Domain is not set with flatten: %d',$do->id));
$zones = $do->zones->pluck('zone_id');
$o = (new self)
->select('addresses.*')
->join('zones',['zones.id'=>'addresses.zone_id'])
->when($trashed,function($query) {
$query->withTrashed();
},function($query) {
$query->active();
})
->whereIN('zones.zone_id',$zones)
->where(function($q) use ($host) {
return $q
->where(function($q) use ($host) {
return $q->where('region_id',$host)
->where('host_id',$host);
})
->orWhere('host_id',$host);
})
->where('node_id',$node)
->where('point_id',$point)
->where('zones.domain_id',$do->id)
->single();
return $o;
}
/**
* Create an activation code for this address
*
* @param User $uo
* @return string
*/
public function set_activation(User $uo): string
{
return sprintf('%x:%s',
$this->id,
substr(md5(sprintf('%d:%x',$uo->id,timew($this->updated_at))),0,10)
);
}
/**
* Check the user's activation code for this address is correct
*
* @param User $uo
* @param string $code
* @return bool
*/
public function check_activation(User $uo,string $code): bool
{
try {
Log::info(sprintf('%s:Checking Activation code [%s] is valid for user [%d]',self::LOGKEY,$code,$uo->id));
return ($code === $this->set_activation($uo));
} catch (\Exception $e) {
Log::error(sprintf('%s:! Activation code [%s] invalid for user [%d]',self::LOGKEY,$code,$uo->id));
return FALSE;
}
}
/** /**
* Files waiting to be sent to this system * Files waiting to be sent to this system
* *
@ -937,6 +963,7 @@ class Address extends Model
* @param bool $update * @param bool $update
* @param Collection|null $echomail * @param Collection|null $echomail
* @return Packet|null * @return Packet|null
* @throws \Exception
* @todo If we export to uplink hubs without our address in the seenby, they should send the message back to * @todo If we export to uplink hubs without our address in the seenby, they should send the message back to
* us with their seenby's. * us with their seenby's.
*/ */
@ -1176,36 +1203,6 @@ class Address extends Model
} }
} }
/**
* Parse a string and split it out as an FTN array
*
* @param string $ftn
* @return array
* @throws \Exception
* @todo Move to Static
*/
public static function parseFTN(string $ftn): array
{
if (! preg_match(sprintf('#^%s$#',self::ftn_regex),strtolower($ftn),$matches))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - regex failed',serialize($ftn)));
// Check our numbers are correct.
foreach ([1,2,3] as $i)
if ((! is_numeric($matches[$i])) || ($matches[$i] > self::ADDRESS_FIELD_MAX))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - zone, host, or node address invalid [%d]',$ftn,$matches[$i]));
if ((! empty($matches[4])) AND ((! is_numeric($matches[$i])) || ($matches[4] > self::ADDRESS_FIELD_MAX)))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4]));
return [
'z'=>(int)$matches[1],
'n'=>(int)$matches[2],
'f'=>(int)$matches[3],
'p'=>empty($matches[4]) ? 0 : (int)$matches[4],
'd'=>$matches[5] ?? NULL
];
}
/** /**
* Retrieve the address session details/passwords * Retrieve the address session details/passwords
* *

View File

@ -55,7 +55,7 @@ class AddressLink extends Netmails
$ao->system->sysop, $ao->system->sysop,
$ao->ftn3d, $ao->ftn3d,
url('/link'), url('/link'),
$ao->set_activation($this->uo) $ao->activation_set($this->uo)
)); ));
$o->msg = $msg->render(); $o->msg = $msg->render();