Group [Very WIP]: Add early implementation of group's contacts

This commit is contained in:
veselcraft 2021-10-15 21:43:05 +03:00
parent cb8038590c
commit 594d025ab8
12 changed files with 313 additions and 6 deletions

View file

@ -3,7 +3,7 @@ namespace openvk\Web\Models\Entities;
use openvk\Web\Util\DateTime; use openvk\Web\Util\DateTime;
use openvk\Web\Models\RowModel; use openvk\Web\Models\RowModel;
use openvk\Web\Models\Entities\{User, Manager}; use openvk\Web\Models\Entities\{User, Manager};
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Managers}; use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Managers, Contacts};
use Nette\Database\Table\{ActiveRow, GroupedSelection}; use Nette\Database\Table\{ActiveRow, GroupedSelection};
use Chandler\Database\DatabaseConnection as DB; use Chandler\Database\DatabaseConnection as DB;
use Chandler\Security\User as ChandlerUser; use Chandler\Security\User as ChandlerUser;
@ -301,6 +301,11 @@ class Club extends RowModel
"comment" => $comment, "comment" => $comment,
]); ]);
} }
function getContacts(): \Traversable
{
return (new Contacts)->getByClub($this->getId());
}
function removeManager(User $user): void function removeManager(User $user): void
{ {

View file

@ -0,0 +1,36 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use Chandler\Database\DatabaseConnection;
use openvk\Web\Models\RowModel;
use openvk\Web\Models\Repositories\Contacts;
use openvk\Web\Models\Repositories\{Users, Clubs};
class Contact extends RowModel
{
protected $tableName = "group_contacts";
function getId(): int
{
return $this->getRecord()->id;
}
function getUser(): ?User
{
return (new Users)->get($this->getRecord()->user);
}
function getGroup(): ?Club
{
return (new Clubs)->get($this->getId());
}
function getDescription(): string
{
return ovk_proc_strtr($this->getRecord()->content, 32);
}
function getEmail(): string
{
return $this->getRecord()->email;
}
}

View file

@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories;
use openvk\Web\Models\Entities\Contact;
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection;
class Contacts
{
private $context;
private $contacts;
function __construct()
{
$this->context = DatabaseConnection::i()->getContext();
$this->contacts = $this->context->table("group_contacts");
}
function get(int $id): ?Contact
{
$ar = $this->clubs->get($id);
return is_null($ar) ? NULL : new Contact($ar);
}
function getByClub(int $id): \Traversable
{
$contacts = $this->contacts->where("group", $id)->where("deleted", 0);
return new Util\EntityStream("Contact", $contacts);
}
function getByClubAndUser(int $club, int $user): ?Contact
{
$contact = $this->contacts->where("group", $club)->where("user", $user)->fetch();
return $this->get($contact);
}
}

View file

@ -1,8 +1,8 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Presenters; namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{Club, Photo}; use openvk\Web\Models\Entities\{Club, Photo, Contact};
use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification; use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification;
use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers}; use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Contacts};
final class GroupPresenter extends OpenVKPresenter final class GroupPresenter extends OpenVKPresenter
{ {
@ -131,7 +131,6 @@ final class GroupPresenter extends OpenVKPresenter
$this->flashFail("succ", "Операция успешна", $user->getCanonicalName() . " назначен(а) администратором."); $this->flashFail("succ", "Операция успешна", $user->getCanonicalName() . " назначен(а) администратором.");
} }
} }
} }
function renderEdit(int $id): void function renderEdit(int $id): void
@ -197,6 +196,62 @@ final class GroupPresenter extends OpenVKPresenter
$this->template->views = $club->getPostViewStats(false); $this->template->views = $club->getPostViewStats(false);
} }
function renderContacts(int $id): void
{
$this->assertUserLoggedIn();
$club = $this->clubs->get($id);
$this->template->club = $club;
$this->template->contacts = $club->getContacts()->page($this->queryParam("p") ?? 1);
$this->template->count = $club->getContacts()->size();
$this->template->paginatorConf = (object) [
"count" => $this->template->count,
"page" => $this->queryParam("p") ?? 1,
"amount" => NULL,
"perPage" => OPENVK_DEFAULT_PER_PAGE,
];
}
function renderActionContact(): void
{
$contact;
$id = $this->queryParam("id");
if($this->queryParam("type") == 'delete' || $this->queryParam("type") == 'edit') {
if(!$id)
exit(json_encode([ "error" => tr("error_segmentation") ]));
$contact = (new Contacts)->get($id);
if(!$contact)
exit(json_encode([ "error" => "Contact does not exist" ]));
if(!$contact->getClub()->canBeModifiedBy($this->user->identity ?? NULL) && $contact->getClub()->getOwner()->getId() !== $user->getId())
exit(json_encode([ "error" => "You have no permissions to modify this contact" ]));
}
if($this->queryParam("type") == 'delete') {
$contact->setDeleted(1);
$contact->save();
exit(json_encode([ "status" => 'ok' ]));
} else if ($this->queryParam("type") == 'edit') {
if(!empty($this->queryParam("desc"))) {
$contact->setContent($this->queryParam("desc"));
$contact->save();
exit(json_encode([ "status" => 'ok' ]));
} else
exit(json_encode([ "error" => "Description cannot be empty" ]));
} else if ($this->queryParam("type") == 'create') {
/* ну тут мне впринципе дальше лень делать
$contact = new Contact;
$contact->setGroup();
$contact->save(); */
exit(json_encode([ "error" => "Not implemented yet" ]));
}
}
function renderAdmin(int $clb, int $id): void function renderAdmin(int $clb, int $id): void
{ {
$this->assertUserLoggedIn(); $this->assertUserLoggedIn();

View file

@ -0,0 +1,89 @@
{extends "../@listView.xml"}
{var iterator = $contacts}
{var count = $paginatorConf->count}
{var page = $paginatorConf->page}
{var perPage = 6}
{block title}{_contacts} {$club->getCanonicalName()}{/block}
{block header}
<a href="{$club->getURL()}">{$club->getCanonicalName()}</a>
» {_contacts}
{/block}
{block actions}
{/block}
{* BEGIN ELEMENTS DESCRIPTION *}
{block tabs}
{if $club->canBeModifiedBy($thisUser)}
<div class="tab">
<a href="javascript:void(0)">
{_main}
</a>
</div>
<div class="tab">
<a href="/club{$club->getId()}/followers">
{_followers}
</a>
</div>
<div id="activetabs" class="tab">
<a id="act_tab_a" href="/club{$club->getId()}/contacts">
{_contacts}
</a>
</div>
<div class="tab">
<a href="/club{$club->getId()}/stats">
{_statistics}
</a>
</div>
{/if}
{/block}
{block link|strip|stripHtml}
/id{$x->getId()}
{/block}
{block preview}
<img src="{$x->getUser()->getAvatarURL()}" alt="{$x->getUser()->getCanonicalName()}" width=75 />
{/block}
{block name}
{$x->getUser()->getCanonicalName()}
{/block}
{block description}
<table>
<tbody>
<tr>
<td width="120" valign="top"><span class="nobold">{_"gender"}: </span></td>
<td>{$x->getUser()->isFemale() ? "женский" : "мужской"}</td>
</tr>
<tr>
<td width="120" valign="top"><span class="nobold">{_description}: </span></td>
<td>
{$x->getDescription()}
</td>
</tr>
<tr>
<td width="120" valign="top"><span class="nobold">{_role}: </span></td>
<td>
{$club->canBeModifiedBy($x->getUser()) ? tr("administrator") : tr("follower")}
</td>
</tr>
<tr n:if="$club->canBeModifiedBy($thisUser ?? NULL) && $club->getOwner()->getId() !== $x->getUser()->getId()">
<td width="120" valign="top"><span class="nobold">{_actions}: </span></td>
<td>
<a href="javascript:contactEdit({$x->getUser()->getId()}, {rawurlencode($csrfToken)})">
{_edit}
</a>,
<a href="javascript:contactDelete({$x->getUser()->getId()}, {rawurlencode($csrfToken)})">
{_delete}
</a>
</td>
</tr>
</tbody>
</table>
{/block}

View file

@ -7,7 +7,7 @@
{block content} {block content}
<div class="tabs"> <div class="tabs">
<div id="activetabs" class="tab"> <div class="tab">
<a id="act_tab_a" href="javascript:void(0)"> <a id="act_tab_a" href="javascript:void(0)">
{_main} {_main}
</a> </a>
@ -17,6 +17,11 @@
{_followers} {_followers}
</a> </a>
</div> </div>
<div class="tab">
<a href="/club{$club->getId()}/contacts">
{_contacts}
</a>
</div>
<div class="tab"> <div class="tab">
<a href="/club{$club->getId()}/stats"> <a href="/club{$club->getId()}/stats">
{_statistics} {_statistics}

View file

@ -17,6 +17,31 @@
{* BEGIN ELEMENTS DESCRIPTION *} {* BEGIN ELEMENTS DESCRIPTION *}
{block tabs}
{if $club->canBeModifiedBy($thisUser)}
<div class="tab">
<a href="javascript:void(0)">
{_main}
</a>
</div>
<div id="activetabs" class="tab">
<a id="act_tab_a" href="/club{$club->getId()}/followers">
{_followers}
</a>
</div>
<div class="tab">
<a href="/club{$club->getId()}/contacts">
{_contacts}
</a>
</div>
<div class="tab">
<a href="/club{$club->getId()}/stats">
{_statistics}
</a>
</div>
{/if}
{/block}
{block link|strip|stripHtml} {block link|strip|stripHtml}
/id{$x->getId()} /id{$x->getId()}
{/block} {/block}

View file

@ -104,6 +104,29 @@
<div style="padding:4px"> <div style="padding:4px">
{_"group_type_open"} {_"group_type_open"}
</div> </div>
</div><div>
<div class="content_title_expanded" onclick="hidePanel(this);">
Контакты
</div>
<div>
{var contacts = $club->getContacts()}
<div class="content_subtitle">
{$contacts->size()}
<div style="float:right;">
<a href="/club{$club->getId()}/contacts">{_"all_title"}</a>
</div>
</div>
<div class="group_contact" n:foreach="$contacts->page(1, 5) as $contact">
<avatar>
<img src="{$contact->getUser()->getAvatarUrl()}" style="image-rendering: -webkit-optimize-contrast;" />
</avatar>
<description>
<a href="{$contact->getUser()->getURL()}"><b>{$contact->getUser()->getFullName()}</b></a><br>
{$contact->getDescription()}
</description>
</div>
</div>
</div> </div>
<div> <div>
<div class="content_title_expanded" onclick="hidePanel(this);"> <div class="content_title_expanded" onclick="hidePanel(this);">

View file

@ -37,3 +37,4 @@ services:
- openvk\Web\Models\Repositories\Vouchers - openvk\Web\Models\Repositories\Vouchers
- openvk\Web\Models\Repositories\Gifts - openvk\Web\Models\Repositories\Gifts
- openvk\Web\Models\Repositories\ContentSearchRepository - openvk\Web\Models\Repositories\ContentSearchRepository
- openvk\Web\Models\Repositories\Contacts

View file

@ -145,6 +145,10 @@ routes:
handler: "Group->statistics" handler: "Group->statistics"
- url: "/club{num}/followers" - url: "/club{num}/followers"
handler: "Group->followers" handler: "Group->followers"
- url: "/club{num}/contacts"
handler: "Group->contacts"
- url: "/club{num}/contacts/action"
handler: "Group->actionContact"
- url: "/club{num}/followers/{num}" - url: "/club{num}/followers/{num}"
handler: "Group->admin" handler: "Group->admin"
- url: "/club{num}/setAdmin.jsp" - url: "/club{num}/setAdmin.jsp"

View file

@ -1424,4 +1424,19 @@ body.scrolled .toTop:hover {
#ovkDraw .literally .lc-picker .toolbar-button:hover:not(.disabled), #ovkDraw .literally .horz-toolbar .square-toolbar-button:hover:not(.disabled) { #ovkDraw .literally .lc-picker .toolbar-button:hover:not(.disabled), #ovkDraw .literally .horz-toolbar .square-toolbar-button:hover:not(.disabled) {
border-color: #cdcdcd; border-color: #cdcdcd;
} }
.group_contact {
font-size: 10px;
display: flex;
padding: 5px;
}
.group_contact avatar {
width: 30px;
margin-right: 5px;
}
.group_contact avatar img {
width: 30px;
}

View file

@ -0,0 +1,14 @@
DROP TABLE IF EXISTS `group_contacts`;
CREATE TABLE `group_contacts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`group` bigint(20) unsigned NOT NULL,
`user` bigint(20) unsigned NOT NULL,
`content` varchar(64) COLLATE utf8mb4_general_nopad_ci NOT NULL,
`email` varchar(64) COLLATE utf8mb4_general_nopad_ci DEFAULT NULL,
`deleted` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `group` (`group`),
KEY `user` (`user`),
CONSTRAINT `group_contacts_ibfk_1` FOREIGN KEY (`group`) REFERENCES `groups` (`id`),
CONSTRAINT `group_contacts_ibfk_2` FOREIGN KEY (`user`) REFERENCES `profiles` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_nopad_ci;