Skip to content
This repository was archived by the owner on Oct 24, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 186 additions & 57 deletions src/app/Http/Controllers/UserController.php

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion src/app/Organisation.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App;

use Illuminate\Support\Str;
use Robsonvn\CouchDB\Eloquent\Model as Eloquent;

class Organisation extends Eloquent
Expand All @@ -10,7 +11,12 @@ class Organisation extends Eloquent
protected $collection = 'organisations';

protected $fillable = [
'name', 'website', 'contact_person', 'address', 'county', 'city', 'comments', 'added_by', 'cover'
'name', 'website', 'contact_person', 'address', 'county', 'city', 'comments', 'added_by', 'cover', 'slug'
];

public function setNameAttribute($value){
$this->attributes['name'] = $value;
$this->attributes['slug'] = Str::slug($value);
}

}
82 changes: 82 additions & 0 deletions src/app/Parser/CsvParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace App\Parser;

/**
* Description of CsvParser
*
* @author stefan
*/
class CsvParser
{

protected $file;
/**
* First row of file contains headers
* @var bool
*/
protected $hasHeaders = true;

/**
* Include the headers in the returned data set?
* [header=>value]
*
* $hasHeaders MUST BE TRUE
*
* @var bool
*/
protected $includeHeadersInData = false;

/**
*
* @param string $filePath
* @param boolean $hasHeaders
* @param bool|null $includeHeadersInData
*/
public function __construct(string $filePath, ?bool $hasHeaders = true, ?bool $includeHeadersInData = false)
{
$this->file = fopen($filePath, 'r');
$this->hasHeaders = $hasHeaders;
}

public function parse(): ?iterable
{
if ($this->hasHeaders) {
$headers = array_map('trim', (array)fgetcsv($this->file, 4096));
}

while (!feof($this->file)) {
$data = fgetcsv($this->file, 4096);

if (false === $data) {
return;
}

$row = array_map('trim', (array)$data);

if ($this->hasHeaders && $this->includeHeadersInData) {
if (count($headers) !== count($row)) {
continue;
}
$row = array_combine($headers, $row);
}

yield $row;
}

$this->rewind();

return;
}

public function rewind(): void
{
rewind($this->file);
}

public function __destruct()
{
fclose($this->file);
}

}
277 changes: 277 additions & 0 deletions src/app/Services/User/Import.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
<?php
/*
* This code was developed by NIMA SOFTWARE SRL | nimasoftware.com
* For details contact contact@nimasoftware.com
*/


namespace App\Services\User;


use App\County;
use App\Institution;
use App\Organisation;
use App\User;
use Doctrine\CouchDB\CouchDBException;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

class Import
{

private $rolesList = [];

private $countiesMap = [];

private $errors = [];

private $citiesMap = [];

private $usersCreated = [];

public function __construct()
{
$this->setup();
}

public function setup()
{
$this->rolesList = array_values(config('roles.role'));
$this->prepareCountiesMap();
}

protected function prepareCountiesMap()
{
/** @var \Illuminate\Database\Eloquent\Collection $countys */
$counties = County::all(['_id', "slug", "name"]);
$this->countiesMap = array_column($counties->toArray(), null, 'slug');
}

public function importRescueOfficers(iterable $list, User $importedBy)
{
return $this->import($list, User::ROLE_RESCUE_OFFICER, $importedBy);
}

public function import(iterable $dataset, $userRole, User $importedBy): self
{
if (!in_array($userRole, $this->rolesList)) {
throw new \InvalidArgumentException(
sprintf(
'Invalid user type! Must be one of %s you provided %s',
print_r($this->rolesList, true),
$userRole
)
);
}


/*
* array(7) {
[0]=> "test popescu"
[1]=> "asfa@fas.asd"
[2]=> "Iasi"
[3]=> "Tg. frumos"
[4]=> "123123"
[5]=> "institutie slug"
[6]=> "organizatie slug"
}
Comment on lines +70 to +79
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make the code more easy to read you can replace this comment with some consts and use the consts in the following code:
const NAME = 0;
const EMAIL = 1;
const COUNTY = 2;
const CITY = 3;
const PHONE = 4;
const INSTITUTION = 5;
const ORGANIZATION = 6;

*/
/** @var array $item */
foreach ($dataset as $item) {

$county = $this->getCounty($item[2]);

$city = $this->getCity($item[3], $county);

$userData = [
'name' => $item[0],
'email' => $item[1],
'county' => $county,
'city' => $city,
'password' => Hash::make(Str::random(16)),
'role' => $userRole,
'phone' => $item[4],
'added_by' => $importedBy->_id,
];

$institution = $this->getInstitution($item[5], $importedBy);
if ($institution) {
$userData['institution'] = $institution;
}

$organisation = $this->getOrganisation($item[6], $importedBy);
if ($organisation) {
$userData['organisation'] = $organisation;
}

if ($this->validateUser($userData)) {
/*
* putem face asta intr-un batch insert ?
*/
$user = User::create($userData);

$this->usersCreated[] = $user;
}

}

return $this;
}

protected function getCounty(string $slug): ?array
{
$countySlug = removeDiacritics($slug);

if (!isset($this->countiesMap[$countySlug])) {
$this->errors = addError($this->errors, $slug, 'Judetul nu exista');

return null;
}

return $this->countiesMap[$countySlug];
}

protected function getCity(string $citySlug, array $county): ?array
{
$citySlug = removeDiacritics($citySlug);

if (isset($this->citiesMap[$citySlug])) {
return $this->citiesMap[$citySlug];
}


try {
/**
* this should be cached
* - locally
* - memcached, redis
* -second level cache in ORM ?
*/
$getCity = \DB::connection('statics')->getCouchDBClient()
->createViewQuery('cities', 'slug')
->setKey([$county['_id'], $citySlug])
->execute();

} catch (CouchDBException $e) {

Log::error(
sprintf(
'An error occurred while searching a city in import users service. We search for citySlug: %s and county %s',
$citySlug,
serialize($county)
)
);
Log::error($e->getMessage());
Log::error($e->getTraceAsString());

return null;
}

if (!$getCity->offsetExists(0)) {
$this->errors = addError($this->errors, $citySlug, 'Orasul nu exista');

return null;
}

$city = $getCity->offsetGet(0);

//local cache
$this->citiesMap[$city[$citySlug]] = $city;

return [
"_id" => $city['id'],
"name" => $city['value'],
];

}

protected function getInstitution(?string $slug, User $importedBy): ?array
{
if (!$slug) {
return $importedBy->institution;
}

$institution = Institution::where('slug', '=', $slug)->first();

if (!$institution) {
$this->errors = addError($this->errors, $slug, 'Institutia nu exista');

return null;
}

/*
* ne trebuie ceva sa verificam daca $importedBy are voie sa faca import pe aceasta institutie
*/

return ['_id' => $institution->_id, 'name' => $institution->name];
}

protected function getOrganisation(string $slug, User $importedBy): ?array
{

if (!$slug) {
return null;
}

$organisation = Organisation::where('slug', '=', $slug)->first();

if (!$organisation) {
$this->errors = addError($this->errors, $slug, 'Organizatia nu exista');

return null;
}

/*
* ne trebuie ceva sa verificam daca $importedBy are voie sa faca import pe aceasta organizatie
*/

return ['_id' => $organisation->_id, 'name' => $organisation->name];
}

protected function validateUser(array $userData)
{
//taken from UserController::store()
$rules = [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users.users',
'role' => 'required',
'phone' => 'required|string|min:6|',
];

$validator = Validator::make($userData, $rules);
if ($validator->fails()) {

foreach ($validator->errors()->messages() as $key => $error) {

$this->errors = addError($this->errors, $key, $error);
}

return false;
}

return true;
}

public function getErrors(): array
{
return $this->errors;
}

public function getTotalImported(): int
{
return count($this->usersCreated);
}

public function hasErrors(): bool
{
return count($this->errors) > 0;
}

public function getCreatedUsers(): array
{
return $this->usersCreated;
}

}
Loading