Skip to content

Commit

Permalink
New feature: set a note as favorite (star/unstar) (#248)
Browse files Browse the repository at this point in the history
* New feature: set note as favorite (star/unstar)

* fix use of hidden classes

* minor optimizations requested by Henni

* remove array annotation

* check if tagger is null

* adjust tests for new favorite feature

* allow setting favorite over API
  • Loading branch information
korelstar authored and Henni committed Oct 21, 2016
1 parent bbae651 commit c4726b8
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 18 deletions.
1 change: 1 addition & 0 deletions appinfo/routes.php
Expand Up @@ -18,6 +18,7 @@
['name' => 'notes#get', 'url' => '/notes/{id}', 'verb' => 'GET'],
['name' => 'notes#create', 'url' => '/notes', 'verb' => 'POST'],
['name' => 'notes#update', 'url' => '/notes/{id}', 'verb' => 'PUT'],
['name' => 'notes#favorite', 'url' => '/notes/{id}/favorite', 'verb' => 'PUT'],
['name' => 'notes#destroy', 'url' => '/notes/{id}', 'verb' => 'DELETE'],

// api
Expand Down
12 changes: 10 additions & 2 deletions controller/notesapicontroller.php
Expand Up @@ -125,11 +125,19 @@ public function create($content) {
*
* @param int $id
* @param string $content
* @param boolean $favorite
* @return DataResponse
*/
public function update($id, $content) {
public function update($id, $content=null, $favorite=null) {
if($favorite!==null) {
$this->service->favorite($id, $favorite, $this->userId);
}
return $this->respond(function () use ($id, $content) {
return $this->service->update($id, $content, $this->userId);
if($content===null) {
return $this->service->get($id, $this->userId);
} else {
return $this->service->update($id, $content, $this->userId);
}
});
}

Expand Down
16 changes: 15 additions & 1 deletion controller/notescontroller.php
Expand Up @@ -105,6 +105,20 @@ public function update($id, $content) {
}


/**
* @NoAdminRequired
*
* @param int $id
* @param boolean $favorite
* @return DataResponse
*/
public function favorite($id, $favorite) {
return $this->respond(function () use ($id, $favorite) {
return $this->notesService->favorite($id, $favorite, $this->userId);
});
}


/**
* @NoAdminRequired
*
Expand All @@ -118,4 +132,4 @@ public function destroy($id) {
});
}

}
}
9 changes: 7 additions & 2 deletions css/notes.css
Expand Up @@ -42,10 +42,15 @@
display: none;
}

#app-navigation .active > .utils .icon-delete {
display: block;
#app-navigation .active > .utils .icon-delete,
#app-navigation .active > .utils .icon-star {
display: inline-block;
opacity: .3;
}
#app-navigation .utils .icon-starred {
display: inline-block;
opacity: 1 !important;
}

.tooltip {
text-shadow: none;
Expand Down
13 changes: 10 additions & 3 deletions db/note.php
Expand Up @@ -24,31 +24,38 @@
* @method void setTitle(string $value)
* @method string getContent()
* @method void setContent(string $value)
* @method boolean getFavorite()
* @method void setFavorite(boolean $value)
* @package OCA\Notes\Db
*/
class Note extends Entity {

public $modified;
public $title;
public $content;
public $favorite = false;

public function __construct() {
$this->addType('modified', 'integer');
$this->addType('favorite', 'boolean');
}

/**
* @param File $file
* @return static
*/
public static function fromFile(File $file){
public static function fromFile(File $file, $tags=[]){
$note = new static();
$note->setId($file->getId());
$note->setContent($file->getContent());
$note->setModified($file->getMTime());
$note->setTitle(pathinfo($file->getName(),PATHINFO_FILENAME)); // remove extension
if(is_array($tags) && in_array(\OC\Tags::TAG_FAVORITE, $tags)) {
$note->setFavorite(true);
//unset($tags[array_search(\OC\Tags::TAG_FAVORITE, $tags)]);
}
$note->resetUpdatedFields();
return $note;
}


}
}
8 changes: 8 additions & 0 deletions js/app/controllers/notescontroller.js
Expand Up @@ -35,4 +35,12 @@ app.controller('NotesController', function($routeParams, $scope, $location,
});
};

$scope.toggleFavorite = function (noteId) {
var note = NotesModel.get(noteId);
note.customPUT({favorite: !note.favorite},
'favorite', {}, {}).then(function (favorite) {
note.favorite = favorite ? true : false;
});
};

});
3 changes: 2 additions & 1 deletion js/app/services/notesmodel.js
Expand Up @@ -35,6 +35,7 @@ app.factory('NotesModel', function () {
note.title = updated.title;
note.modified = updated.modified;
note.content = updated.content;
note.favorite = updated.favorite;
} else {
this.notes.push(updated);
this.notesIds[updated.id] = updated;
Expand All @@ -53,4 +54,4 @@ app.factory('NotesModel', function () {
};

return new NotesModel();
});
});
2 changes: 1 addition & 1 deletion js/public/app.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion js/public/app.min.js.map

Large diffs are not rendered by default.

54 changes: 48 additions & 6 deletions service/notesservice.php
Expand Up @@ -44,13 +44,23 @@ public function __construct (IRootFolder $root, IL10N $l10n) {
public function getAll ($userId){
$folder = $this->getFolderForUser($userId);
$files = $folder->getDirectoryListing();
$notes = [];

$filesById = [];
foreach($files as $file) {
if($this->isNote($file)) {
$notes[] = Note::fromFile($file);
$filesById[$file->getId()] = $file;
}
}
$tagger = \OC::$server->getTagManager()->load('files');
if($tagger==null) {
$tags = [];
} else {
$tags = $tagger->getTagsForObjects(array_keys($filesById));
}

$notes = [];
foreach($filesById as $id=>$file) {
$notes[] = Note::fromFile($file, array_key_exists($id, $tags) ? $tags[$id] : []);
}

return $notes;
}
Expand All @@ -65,9 +75,18 @@ public function getAll ($userId){
*/
public function get ($id, $userId) {
$folder = $this->getFolderForUser($userId);
return Note::fromFile($this->getFileById($folder, $id));
return Note::fromFile($this->getFileById($folder, $id), $this->getTags($id));
}

private function getTags ($id) {
$tagger = \OC::$server->getTagManager()->load('files');
if($tagger==null) {
$tags = [];
} else {
$tags = $tagger->getTagsForObjects([$id]);
}
return array_key_exists($id, $tags) ? $tags[$id] : [];
}

/**
* Creates a note and returns the empty note
Expand Down Expand Up @@ -131,7 +150,31 @@ public function update ($id, $content, $userId){

$file->putContent($content);

return Note::fromFile($file);
return Note::fromFile($file, $this->getTags($id));
}


/**
* Set or unset a note as favorite.
* @param int $id the id of the note used to update
* @param boolean $favorite whether the note should be a favorite or not
* @throws NoteDoesNotExistException if note does not exist
* @return boolean the new favorite state of the note
*/
public function favorite ($id, $favorite, $userId){
$folder = $this->getFolderForUser($userId);
$file = $this->getFileById($folder, $id);
if(!$this->isNote($file)) {
throw new NoteDoesNotExistException();
}
$tagger = \OC::$server->getTagManager()->load('files');
if($favorite)
$tagger->addToFavorites($id);
else
$tagger->removeFromFavorites($id);

$tags = $tagger->getTagsForObjects([$id]);
return in_array(\OC\Tags::TAG_FAVORITE, $tags[$id]);
}


Expand Down Expand Up @@ -161,7 +204,6 @@ private function getFileById ($folder, $id) {
if(count($file) <= 0 || !$this->isNote($file[0])) {
throw new NoteDoesNotExistException();
}

return $file[0];
}

Expand Down
8 changes: 7 additions & 1 deletion templates/main.php
Expand Up @@ -42,7 +42,7 @@
<a href='#'>+ <span><?php p($l->t('New note')); ?></span></a>
</li>
<!-- notes list -->
<li ng-repeat="note in notes|orderBy:'modified':'reverse'"
<li ng-repeat="note in notes|orderBy:['-favorite','-modified']"
ng-class="{ active: note.id == route.noteId }">
<a href="#/notes/{{ note.id }}">
{{ note.title | noteTitle }}
Expand All @@ -53,6 +53,12 @@
notes-tooltip
data-placement="bottom"
ng-click="delete(note.id)"></button>
<button class="svg action icon-star"
title="<?php p($l->t('Favorite')); ?>"
notes-tooltip
data-placement="bottom"
ng-click="toggleFavorite(note.id)"
ng-class="{'icon-starred': note.favorite}"></button>
</span>
</li>

Expand Down
3 changes: 3 additions & 0 deletions tests/unit/controller/NotesApiControllerTest.php
Expand Up @@ -88,10 +88,12 @@ public function testGetAllHide(){
$this->assertEquals(json_encode([
[
'modified' => 123,
'favorite' => false,
'id' => 3,
],
[
'modified' => 111,
'favorite' => false,
'id' => 4,
]
]), json_encode($response->getData()));
Expand Down Expand Up @@ -136,6 +138,7 @@ public function testGetHide(){

$this->assertEquals(json_encode([
'modified' => 123,
'favorite' => false,
'id' => 3,
]), json_encode($response->getData()));
$this->assertTrue($response instanceof DataResponse);
Expand Down

0 comments on commit c4726b8

Please sign in to comment.