[Feature] Added privileges checks.
Fixed playlist.name and playlist.thumbnailURI setters to update values also in DB.
Still needed to add filesystem-based "if uri points to real file" check.
[Verification] Code compiles without errors.
Checked in console. Setting name or thumbnailURI always update values in DB.
TCT results: all/ passed/ failed/ timeout/ Not run
before: 244/231/12/1/0
after: 244/232/11/1/0
Change-Id: I9d9bf44294a56d58d54cd23fc68abf58262a013c
Signed-off-by: Piotr Kosko <p.kosko@samsung.com>
namespace {
// The privileges that required in Content API
-const std::string kPrivilegeContent = "";
+const std::string kPrivilegeContentRead = "http://tizen.org/privilege/content.read";
+const std::string kPrivilegeContentWrite = "http://tizen.org/privilege/content.write";
} // namespace
REGISTER_SYNC("ContentPlaylist_move", ContentManagerPlaylistMove);
REGISTER_SYNC("ContentManager_getLyrics", ContentManagerAudioGetLyrics);
+ REGISTER_SYNC("ContentPlaylist_getName", PlaylistGetName);
+ REGISTER_SYNC("ContentPlaylist_setName", PlaylistSetName);
+ REGISTER_SYNC("ContentPlaylist_getThumbnailUri", PlaylistGetThumbnailUri);
+ REGISTER_SYNC("ContentPlaylist_setThumbnailUri", PlaylistSetThumbnailUri);
#undef REGISTER_SYNC
}
void ContentInstance::ContentManagerUpdate(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
int ret;
if (ContentManager::getInstance()->isConnected()) {
ret = ContentManager::getInstance()->update(args);
void ContentInstance::ContentManagerUpdatebatch(const picojson::value& args, picojson::object& out) {
LoggerE("entered");
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
double callbackId = args.get("callbackId").get<double>();
auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
}
void ContentInstance::ContentManagerFind(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
CHECK_EXIST(args, "callbackId", out)
double callbackId = args.get("callbackId").get<double>();
}
void ContentInstance::ContentManagerScanfile(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
CHECK_EXIST(args, "callbackId", out)
CHECK_EXIST(args, "contentURI", out)
void ContentInstance::ContentManagerSetchangelistener(const picojson::value& args,
picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
CHECK_EXIST(args, "listenerId", out)
ReplyCallbackData* cbData = new ReplyCallbackData();
}
void ContentInstance::ContentManagerUnsetchangelistener(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
if (ContentManager::getInstance()->unSetChangeListener().IsError()) {
LoggerD("unsuccesfull deregistering of callback");
}
}
-
void ContentInstance::ContentManagerGetplaylists(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
CHECK_EXIST(args, "callbackId", out)
double callbackId = args.get("callbackId").get<double>();
}
void ContentInstance::ContentManagerCreateplaylist(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
CHECK_EXIST(args, "callbackId", out)
CHECK_EXIST(args, "name", out)
common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
}
void ContentInstance::ContentManagerRemoveplaylist(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
double callbackId = args.get("callbackId").get<double>();
auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
}
void ContentInstance::ContentManagerPlaylistAdd(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
int ret;
if(ContentManager::getInstance()->isConnected()) {
std::string playlist_id = args.get("playlistId").get<std::string>();
}
void ContentInstance::ContentManagerPlaylistAddbatch(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
LoggerE("entered");
double callbackId = args.get("callbackId").get<double>();
void ContentInstance::ContentManagerPlaylistGet(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
LoggerE("entered");
double callbackId = args.get("callbackId").get<double>();
}
void ContentInstance::ContentManagerPlaylistRemove(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
int ret;
if(ContentManager::getInstance()->isConnected()) {
std::string playlist_id = args.get("playlistId").get<std::string>();
}
void ContentInstance::ContentManagerPlaylistRemovebatch(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
LoggerE("entered");
double callbackId = args.get("callbackId").get<double>();
void ContentInstance::ContentManagerPlaylistSetorder(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
LoggerE("entered");
double callbackId = args.get("callbackId").get<double>();
}
void ContentInstance::ContentManagerPlaylistMove(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
LoggerE("entered");
double callbackId = args.get("callbackId").get<double>();
}
}
+void ContentInstance::PlaylistGetName(const picojson::value& args, picojson::object& out) {
+ int ret;
+ CHECK_EXIST(args, "id", out)
+ int id = static_cast<int>(args.get("id").get<double>());
+ std::string name;
+ ret = ContentManager::getInstance()->getPlaylistName(id, &name);
+ if(ret != MEDIA_CONTENT_ERROR_NONE) {
+ ReportError(ContentManager::getInstance()->convertError(ret), &out);
+ } else {
+ ReportSuccess(picojson::value(name),out);
+ }
+}
+
+void ContentInstance::PlaylistSetName(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
+ int ret;
+ CHECK_EXIST(args, "id", out)
+ CHECK_EXIST(args, "name", out)
+ int id = static_cast<int>(args.get("id").get<double>());
+ std::string name = args.get("name").get<std::string>();
+ ret = ContentManager::getInstance()->setPlaylistName(id, name);
+ if(ret != MEDIA_CONTENT_ERROR_NONE) {
+ ReportError(ContentManager::getInstance()->convertError(ret), &out);
+ } else {
+ ReportSuccess(out);
+ }
+}
+
+void ContentInstance::PlaylistGetThumbnailUri(const picojson::value& args, picojson::object& out) {
+ int ret;
+ CHECK_EXIST(args, "id", out)
+ int id = static_cast<int>(args.get("id").get<double>());
+ std::string uri;
+ ret = ContentManager::getInstance()->getThumbnailUri(id, &uri);
+ if(ret != MEDIA_CONTENT_ERROR_NONE) {
+ ReportError(ContentManager::getInstance()->convertError(ret), &out);
+ } else {
+ ReportSuccess(picojson::value(uri),out);
+ }
+}
+
+void ContentInstance::PlaylistSetThumbnailUri(const picojson::value& args, picojson::object& out) {
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
+ int ret;
+ CHECK_EXIST(args, "id", out)
+ CHECK_EXIST(args, "uri", out)
+ int id = static_cast<int>(args.get("id").get<double>());
+ std::string uri = args.get("uri").get<std::string>();
+ ret = ContentManager::getInstance()->setThumbnailUri(id, uri);
+ if(ret != MEDIA_CONTENT_ERROR_NONE) {
+ ReportError(ContentManager::getInstance()->convertError(ret), &out);
+ } else {
+ ReportSuccess(out);
+ }
+}
+
#undef CHECK_EXIST
} // namespace content
void ContentManagerPlaylistMove(const picojson::value& args, picojson::object& out);
void ContentManagerAudioGetLyrics(const picojson::value& args, picojson::object& out);
-//
+ void PlaylistGetName(const picojson::value& args, picojson::object& out);
+ void PlaylistSetName(const picojson::value& args, picojson::object& out);
+ void PlaylistGetThumbnailUri(const picojson::value& args, picojson::object& out);
+ void PlaylistSetThumbnailUri(const picojson::value& args, picojson::object& out);
};
typedef struct _ReplyCallbackData{
namespace extension {
namespace content {
+namespace {
+static const std::string uri_prefix = "file://";
+static const std::string uri_absolute_prefix = "file:///";
+}
+
const std::map<std::string, media_content_orientation_e> orientationMap = {
{"NORMAL", MEDIA_CONTENT_ORIENTATION_NORMAL},
{"FLIP_HORIZONTAL", MEDIA_CONTENT_ORIENTATION_HFLIP},
return ret;
}
+media_playlist_h getPlaylistHandle(int id)
+{
+ LoggerD("Entered");
+ media_playlist_h playlist_handle = nullptr;
+ int ret_code = media_playlist_get_playlist_from_db(id, &playlist_handle);
+ if(MEDIA_CONTENT_ERROR_NONE != ret_code ||
+ playlist_handle == nullptr) {
+ LoggerE("could not get playlist handle for id: %d", id);
+ return nullptr;
+ }
+
+ return playlist_handle;
+}
+
+void destroyMediaPlaylistHandle(media_playlist_h& playlist_handle)
+{
+ LoggerD("Entered");
+ if(playlist_handle) {
+ int ret_code = media_playlist_destroy(playlist_handle);
+ playlist_handle = nullptr;
+
+ if(MEDIA_CONTENT_ERROR_NONE != ret_code) {
+ LoggerE("media_playlist_destroy failed");
+ }
+ }
+}
+
+int ContentManager::getPlaylistName(int id, std::string* result) {
+ LoggerD("Entered");
+ media_playlist_h playlist_handle = getPlaylistHandle(id);
+ PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
+
+ char* tmp_playlist_name = nullptr;
+ const int ret_code = media_playlist_get_name(playlist_handle, &tmp_playlist_name);
+
+ if(MEDIA_CONTENT_ERROR_NONE != ret_code) {
+ LoggerE("media_playlist_get_name failed");
+ return TIZEN_ERROR_UNKNOWN;
+ }
+
+ std::string playlist_name;
+ if(tmp_playlist_name) {
+ playlist_name = tmp_playlist_name;
+ free(tmp_playlist_name);
+ tmp_playlist_name = nullptr;
+ }
+
+ *result = playlist_name;
+ return MEDIA_CONTENT_ERROR_NONE;
+}
+
+int updatePlaylistInDB(media_playlist_h playlist_handle)
+{
+ LoggerD("Entered");
+ int ret_code = media_playlist_update_to_db(playlist_handle);
+ if(MEDIA_CONTENT_ERROR_NONE != ret_code) {
+ LoggerE("media_playlist_update_to_db failed");
+ return TIZEN_ERROR_UNKNOWN;
+ }
+ return MEDIA_CONTENT_ERROR_NONE;
+}
+
+int ContentManager::setPlaylistName(int id, const std::string& name)
+{
+ LoggerD("Entered");
+ if(name.empty()) {
+ LoggerE("Cannot set empty playlist name!");
+ return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
+ }
+
+ media_playlist_h playlist_handle = getPlaylistHandle(id);
+ PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
+
+ const int ret_code = media_playlist_set_name(playlist_handle, name.c_str());
+ if(MEDIA_CONTENT_ERROR_NONE != ret_code) {
+ LoggerE("media_playlist_set_name failed");
+ //Setting name that is used by other playlist does not return bad error code here.
+ //MEDIA_CONTENT_ERROR_INVALID_OPERATION is being returned in updatePlaylistInDB
+ return TIZEN_ERROR_UNKNOWN;
+ }
+
+ int ret = updatePlaylistInDB(playlist_handle);
+ if (MEDIA_CONTENT_ERROR_NONE != ret) {
+ LoggerE("Error while updating playlist: %d", ret);
+ if (MEDIA_CONTENT_ERROR_INVALID_OPERATION == ret) {
+ //We could fetch list of playlists and check if other playlist is using this
+ //name, but that seems to be to much work in synchronous method
+ LoggerE("Playlist name: %s is probably already used", name.c_str());
+ }
+ return ret;
+ }
+ return MEDIA_CONTENT_ERROR_NONE;
+}
+
+int ContentManager::getThumbnailUri(int id, std::string* result)
+{
+ LoggerD("Entered");
+ media_playlist_h playlist_handle = getPlaylistHandle(id);
+ PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
+
+ char* tmp_playlist_thb_path = nullptr;
+ const int ret_code = media_playlist_get_thumbnail_path(playlist_handle, &tmp_playlist_thb_path);
+
+ if(MEDIA_CONTENT_ERROR_NONE != ret_code) {
+ LoggerE("media_playlist_get_name failed");
+ return TIZEN_ERROR_UNKNOWN;
+ }
+
+ std::string playlist_thb_path;
+ if(tmp_playlist_thb_path) {
+ playlist_thb_path = tmp_playlist_thb_path;
+ free(tmp_playlist_thb_path);
+ tmp_playlist_thb_path = nullptr;
+ }
+
+ *result = playlist_thb_path;
+ return MEDIA_CONTENT_ERROR_NONE;
+}
+
+int ContentManager::setThumbnailUri(int id, const std::string& thb_uri)
+{
+ LoggerD("Entered");
+
+ //Allow setting empty URI, unfortunately Core API does not allow to set empty
+ //path so we need to set one empty space. This is probably issue of Core API.
+ if(!thb_uri.empty() && " " != thb_uri) {
+ /// TODO what if uri holds virtual path
+ if(thb_uri.find(uri_absolute_prefix) != 0) {
+ LoggerE("thumbnail URI is not valid: [%s]", thb_uri.c_str());
+ return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
+ }
+
+ std::string absoulte_path = thb_uri.substr(uri_prefix.length());
+ /// TODO check if uri points an existing file
+ }
+
+ media_playlist_h playlist_handle = getPlaylistHandle(id);
+ PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
+
+ const int ret_code = media_playlist_set_thumbnail_path(playlist_handle,
+ thb_uri.c_str());
+ if(MEDIA_CONTENT_ERROR_NONE != ret_code) {
+ LoggerE("media_playlist_set_thumbnail_path failed");
+ return TIZEN_ERROR_UNKNOWN;
+ }
+
+ int ret = updatePlaylistInDB(playlist_handle);
+ return ret;
+}
PlatformResult ContentManager::convertError(int err) {
switch (err) {
namespace extension {
namespace content {
+typedef std::unique_ptr<std::remove_pointer<media_playlist_h>::type,
+ void (*)(media_playlist_h&)> PlaylistUniquePtr;
+
void ContentToJson(media_info_h info, picojson::object& o);
class ContentManager {
void playlistSetOrder(const std::shared_ptr<ReplyCallbackData>& user_data);
void playlistMove(const std::shared_ptr<ReplyCallbackData>& user_data);
+ int getPlaylistName(int id, std::string* result);
+ int setPlaylistName(int id, const std::string& name);
+
+ int getThumbnailUri(int id, std::string* result);
+ int setThumbnailUri(int id, const std::string& thb_uri);
+
//playlistSetOrder
common::PlatformResult convertError(int err);
private:
function Playlist(data) {
var editableAttributes = ['name', 'thumbnailURI'];
var id;
- var name;
var numberOfTracks;
- var thumbnailURI = null;
Object.defineProperties(this, {
editableAttributes: {
},
name: {
get: function() {
- return name;
+ var result = native_.callSync('ContentPlaylist_getName', {'id' : Number(id)});
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+ return native_.getResultObject(result);
},
set: function(v) {
if (!type_.isNull(v)) {
- name = converter_.toString(v, false);
+ var name = converter_.toString(v, false);
+ var result = native_.callSync('ContentPlaylist_setName',
+ {'id' : Number(id), 'name' : name});
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
}
},
enumerable: true
},
thumbnailURI: {
get: function() {
- return thumbnailURI;
+ var result = native_.callSync('ContentPlaylist_getThumbnailUri', {'id' : Number(id)});
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
+ var res = native_.getResultObject(result);
+ //CoreAPI not support empty thumbnail, so one space must be used instead null thumbnail
+ return res === " " ? null : res;
},
set: function(v) {
- thumbnailURI = converter_.toString(v, true);
+ var thumbnailURI = converter_.toString(v, true);
+ if (type_.isNullOrUndefined(thumbnailURI)) {
+ //CoreAPI not support empty thumbnail, so one space must be used instead null thumbnail
+ thumbnailURI = " ";
+ }
+ //TODO probably thumbnailURI should be converted here to absolute uri in case of virtual
+ var result = native_.callSync('ContentPlaylist_setThumbnailUri',
+ {'id' : Number(id), 'uri' : thumbnailURI});
+ if (native_.isFailure(result)) {
+ throw native_.getErrorObject(result);
+ }
},
enumerable: true
},