Fix backend to shared notes, and initial fronted code.

This commit is contained in:
Matias De lellis
2020-06-15 19:25:48 -03:00
parent 5f327bc136
commit c09c3aacb4
8 changed files with 126 additions and 63 deletions

View File

@@ -226,7 +226,8 @@ div[contenteditable="true"] {
border: none; border: none;
} }
.note-options { .note-options,
.note-disable-options {
padding: 8px; padding: 8px;
padding-top: 0px; padding-top: 0px;
} }
@@ -249,6 +250,7 @@ div[contenteditable="true"] {
opacity: 0.5; opacity: 0.5;
} }
.slim-share,
.slim-tag { .slim-tag {
display: inline-block; display: inline-block;
cursor: pointer; cursor: pointer;
@@ -260,6 +262,7 @@ div[contenteditable="true"] {
font-size: 90%; font-size: 90%;
} }
.slim-share:hover,
.slim-tag:hover { .slim-tag:hover {
background-color: rgba(0,0,0,0.12); background-color: rgba(0,0,0,0.12);
} }

View File

@@ -164,11 +164,12 @@ View.prototype = {
this._editableContent(note.content); this._editableContent(note.content);
this._editablePinned(note.ispinned); this._editablePinned(note.ispinned);
this._editableColor(note.color); this._editableColor(note.color);
this._editableShares(note.shared_by, note.shared_with);
this._editableTags(note.tags); this._editableTags(note.tags);
this._editableAttachts(note.attachts); this._editableAttachts(note.attachts);
// Create medium div editor. // Create medium div editor.
this._initEditor(); this._isEditable(!note.is_shared);
// Show modal editor // Show modal editor
this._showEditor(id); this._showEditor(id);
@@ -490,6 +491,12 @@ View.prototype = {
); );
}); });
// handle cancel editing notes.
$('#modal-note-div #close-button').click(function (event) {
event.stopPropagation();
self.cancelEdit();
});
// handle cancel editing notes. // handle cancel editing notes.
$('#modal-note-div #cancel-button').click(function (event) { $('#modal-note-div #cancel-button').click(function (event) {
event.stopPropagation(); event.stopPropagation();
@@ -655,6 +662,24 @@ View.prototype = {
return digits[1] + '#' + rgb.toString(16).toUpperCase(); return digits[1] + '#' + rgb.toString(16).toUpperCase();
}, },
_isEditable: function(editable) {
if (editable === undefined)
return $('#title-editable').prop('contenteditable');
else {
if (editable) {
$('#title-editable').prop('contenteditable', true);
$('#modal-note-div .icon-header-note').show();
$('#modal-note-div .note-options').show();
$('#modal-note-div .note-disable-options').hide();
this._initEditor();
} else {
$('#modal-note-div .note-options').hide();
$('#modal-note-div .icon-header-note').hide();
$('#title-editable').removeAttr("contentEditable");
$('#modal-note-div .note-disable-options').show();
}
}
},
_editableId: function(id) { _editableId: function(id) {
if (id === undefined) if (id === undefined)
return $("#modal-note-div .quicknote").data('id'); return $("#modal-note-div .quicknote").data('id');
@@ -706,6 +731,19 @@ View.prototype = {
$("#modal-note-div .quicknote").css("background-color", color); $("#modal-note-div .quicknote").css("background-color", color);
} }
}, },
_editableShares: function(shared_by, shared_with) {
if (shared_with === undefined) {
return $("#modal-note-div .slim-share").toArray().map(function (value) {
return {
id: value.getAttribute('tag-id'),
name: value.textContent.trim()
};
});
} else {
var html = Handlebars.templates['shares']({ shared_by: shared_by, shared_with: shared_with});
$("#modal-note-div .note-shares").replaceWith(html);
}
},
_editableTags: function(tags) { _editableTags: function(tags) {
if (tags === undefined) { if (tags === undefined) {
return $("#modal-note-div .slim-tag").toArray().map(function (value) { return $("#modal-note-div .slim-tag").toArray().map(function (value) {
@@ -797,8 +835,10 @@ View.prototype = {
this._editor = editor; this._editor = editor;
}, },
_destroyEditor: function() { _destroyEditor: function() {
if (this._editor != undefined) {
this._editor.destroy(); this._editor.destroy();
this._editor = undefined; this._editor = undefined;
}
this._changed = false; this._changed = false;
this._editableId(-1); this._editableId(-1);
@@ -821,7 +861,6 @@ View.prototype = {
"left" : note.offset().left, "left" : note.offset().left,
"top" : note.offset().top, "top" : note.offset().top,
"width" : note.width(), "width" : note.width(),
"min-height": note.height(),
"height:" : "auto" "height:" : "auto"
}); });

View File

@@ -2,18 +2,7 @@
<div id="notes-grid-div" class="notes-grid"> <div id="notes-grid-div" class="notes-grid">
{{#each notes}} {{#each notes}}
<div class="note-grid-item"> <div class="note-grid-item">
<div class="quicknote noselect {{#if isshared}}shared{{/if}} {{#if sharedwith}}shareowner{{/if}}" style="background-color: {{color}}" data-id="{{ id }}" data-timestamp="{{ timestamp }}" > <div class="quicknote noselect" style="background-color: {{color}}" data-id="{{ id }}" data-timestamp="{{ timestamp }}" >
{{#if isshared}}
<div>
<div class='icon-share shared-title' title="Shared by {{ userid }}"></div>
<div class='note-title'>
{{{ title }}}
</div>
</div>
<div id='content' class='note-content'>
{{{ content }}}
</div>
{{else}}
<div class='note-header'> <div class='note-header'>
<div class='note-attachts'> <div class='note-attachts'>
{{#each attachts}} {{#each attachts}}
@@ -25,17 +14,14 @@
</div> </div>
<div class='note-body'> <div class='note-body'>
<div> <div>
{{#unless is_shared}}
{{#if ispinned}} {{#if ispinned}}
<div class="icon-header-note icon-pinned fixed-header-icon" title="{{t "quicknotes" "Unpin note"}}"></div> <div class="icon-header-note icon-pinned fixed-header-icon" title="{{t "quicknotes" "Unpin note"}}"></div>
{{else}} {{else}}
<div class="icon-header-note icon-pin hide-header-icon" title="{{t "quicknotes" "Pin note"}}"></div> <div class="icon-header-note icon-pin hide-header-icon" title="{{t "quicknotes" "Pin note"}}"></div>
{{/if}} {{/if}}
{{/unless}}
<div class="icon-header-note icon-delete hide-header-icon icon-delete-note" title="{{t "quicknotes" "Delete note"}}"></div> <div class="icon-header-note icon-delete hide-header-icon icon-delete-note" title="{{t "quicknotes" "Delete note"}}"></div>
<!--
{{#if sharedwith}}
<div class='icon-share shared-title-owner' title="Shared with {{ sharedwith }}"></div>
{{/if}}
-->
<div class='note-title'> <div class='note-title'>
{{{ title }}} {{{ title }}}
</div> </div>
@@ -43,6 +29,14 @@
<div class='note-content'> <div class='note-content'>
{{{ content }}} {{{ content }}}
</div> </div>
<div class='note-shares'>
{{#each shared_with}}
<div class="icon-user slim-share" share-id="{{ id }}" title="Shared with {{ shared_user }}">{{{ shared_user }}}</div>
{{/each}}
{{#each shared_by}}
<div class="icon-user slim-share" share-id="{{ id }}" title="Shared by {{ user_id }}">{{{ user_id }}}</div>
{{/each}}
</div>
<div class='note-tags'> <div class='note-tags'>
{{#each tags}} {{#each tags}}
<div class='icon-tag slim-tag' tag-id="{{ id }}"> <div class='icon-tag slim-tag' tag-id="{{ id }}">
@@ -51,7 +45,6 @@
{{/each}} {{/each}}
</div> </div>
</div> </div>
{{/if}}
</div> </div>
</div> </div>
{{/each}} {{/each}}
@@ -68,6 +61,7 @@
<div contenteditable="true" id='title-editable' class='note-title'></div> <div contenteditable="true" id='title-editable' class='note-title'></div>
</div> </div>
<div contenteditable="true" id='content-editable' class='note-content'></div> <div contenteditable="true" id='content-editable' class='note-content'></div>
<div class='note-shares'></div>
<div class='note-tags'></div> <div class='note-tags'></div>
</div> </div>
<div class="note-options"> <div class="note-options">
@@ -87,9 +81,9 @@
<a href="#" class="circle-toolbar" style="background-color: #CECECE"></a> <a href="#" class="circle-toolbar" style="background-color: #CECECE"></a>
</div> </div>
<div class="buttons-toolbar"> <div class="buttons-toolbar">
<!-- <button id='share-button' class='round-tool-button'>
<button id='share-button'><?php p($l->t('Share'));?></button> <div class="icon-shared" title="{{t "quicknotes" "Share note"}}"></div>
--> </button>
<button id='attach-button' class='round-tool-button'> <button id='attach-button' class='round-tool-button'>
<div class="icon-picture" title="{{t "quicknotes" "Attach file"}}"></div> <div class="icon-picture" title="{{t "quicknotes" "Attach file"}}"></div>
</button> </button>
@@ -105,7 +99,11 @@
</div> </div>
<div style="clear: both;"></div> <div style="clear: both;"></div>
</div> </div>
<div class="note-disable-options">
<div class="buttons-toolbar">
<button id='close-button'>{{t "quicknotes" "Close"}}</button>
</div> </div>
<div style="clear: both;"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,8 @@
<div class='note-shares'>
{{#each shared_with}}
<div class="icon-user slim-share" share-id="{{ id }}" title="Shared with {{ shared_user }}">{{{ shared_user }}}</div>
{{/each}}
{{#each shared_by}}
<div class="icon-user slim-share" share-id="{{ id }}" title="Shared from {{ user_id }}">{{{ user_id }}}</div>
{{/each}}
</div>

View File

@@ -13,7 +13,8 @@ class Note extends Entity implements JsonSerializable {
protected $timestamp; protected $timestamp;
protected $colorId; protected $colorId;
protected $userId; protected $userId;
protected $sharedWith; protected $sharedWith = [];
protected $sharedBy = [];
protected $isShared; protected $isShared;
protected $tags; protected $tags;
protected $attachts; protected $attachts;
@@ -40,8 +41,9 @@ class Note extends Entity implements JsonSerializable {
'colorid' => $this->colorId, 'colorid' => $this->colorId,
'color' => $this->color, 'color' => $this->color,
'userid' => $this->userId, 'userid' => $this->userId,
'sharedwith' => $this->sharedWith, 'shared_with' => $this->sharedWith,
'isshared' => $this->isShared, 'shared_by' => $this->sharedBy,
'is_shared' => $this->isShared,
'tags' => $this->tags, 'tags' => $this->tags,
'attachts' => $this->attachts 'attachts' => $this->attachts
]; ];

View File

@@ -31,6 +31,22 @@ class NoteMapper extends QBMapper {
return $this->findEntity($qb); return $this->findEntity($qb);
} }
/**
* @param int $id
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
* @return Note
*/
public function findShared($id) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->tableName)
->where(
$qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))
);
return $this->findEntity($qb);
}
public function findAll($userId) { public function findAll($userId) {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')

View File

@@ -8,15 +8,18 @@ use OCP\AppFramework\Db\Entity;
class NoteShare extends Entity implements JsonSerializable { class NoteShare extends Entity implements JsonSerializable {
protected $noteId; protected $noteId;
protected $userId;
protected $sharedUser; protected $sharedUser;
protected $sharedGroup; protected $sharedGroup;
public function jsonSerialize() { public function jsonSerialize() {
return [ return [
'id' => $this->id, 'id' => $this->id,
'noteid' => $this->noteId, 'user_id' => $this->userId,
'shareduser' => $this->sharedUser, 'note_id' => $this->noteId,
'sharedgroup' => $this->sharedGroup 'shared_user' => $this->sharedUser,
'shared_group' => $this->sharedGroup
]; ];
} }
} }

View File

@@ -75,50 +75,44 @@ class NoteService {
*/ */
public function getAll(string $userId): array { public function getAll(string $userId): array {
$notes = $this->notemapper->findAll($userId); $notes = $this->notemapper->findAll($userId);
// Set shares with others.
foreach($notes as $note) { foreach($notes as $note) {
$note->setIsShared(false); $note->setIsShared(false);
$sharedWith = $this->notesharemapper->getSharesForNote($note->getId()); $note->setSharedWith($this->notesharemapper->getSharesForNote($note->getId()));
if(count($sharedWith) > 0) {
$shareList = array();
foreach($sharedWith as $share) {
$shareList[] = $share->getSharedUser();
}
$note->setSharedWith(implode(", ", $shareList));
} else {
$note->setSharedWith(null);
}
$note->setTags($this->tagmapper->getTagsForNote($userId, $note->getId()));
}
$shareEntries = $this->notesharemapper->findForUser($userId);
$shares = array();
foreach($shareEntries as $entry) {
try {
//find is only to check if current user is owner
$this->notemapper->find($entry->getNoteId(), $userId);
//user is owner, nothing to do
} catch(\OCP\AppFramework\Db\DoesNotExistException $e) {
$share = $this->notemapper->findById($entry->getNoteId());
$share->setIsShared(true);
$shares[] = $share;
} }
// Get shares from others.
$shares = [];
$sharedEntries = $this->notesharemapper->findForUser($userId);
foreach($sharedEntries as $sharedEntry) {
$sharedNote = $this->notemapper->findShared($sharedEntry->getNoteId());
$sharedNote->setIsShared(true);
$sharedEntry->setUserId($sharedNote->getUserId());
$sharedNote->setSharedBy([$sharedEntry]);
$shares[] = $sharedNote;
} }
// Attahch shared notes from others to same response
$notes = array_merge($notes, $shares); $notes = array_merge($notes, $shares);
foreach ($notes as $note) { // Set tags to response.
$note->setTitle(strip_tags($note->getTitle())); foreach($notes as $note) {
$note->setTags($this->tagmapper->getTagsForNote($userId, $note->getId()));
} }
// Insert true color to response // Insert color to response
foreach ($notes as $note) { foreach ($notes as $note) {
$note->setColor($this->colormapper->find($note->getColorId())->getColor()); $note->setColor($this->colormapper->find($note->getColorId())->getColor());
} }
// Insert true color to response // Insert pin to response
foreach ($notes as $note) { foreach ($notes as $note) {
$note->setIsPinned($note->getPinned() ? true : false); $note->setIsPinned($note->getPinned() ? true : false);
} }
// Insert true attachts to response // Insert attachts to response.
foreach ($notes as $note) { foreach ($notes as $note) {
$attachts = $this->attachMapper->findFromNote($userId, $note->getId()); $attachts = $this->attachMapper->findFromNote($userId, $note->getId());
foreach ($attachts as $attach) { foreach ($attachts as $attach) {