1: <?php
2: /**
3: * Jonah external API interface.
4: *
5: * This file defines Jonah's external API interface. Other
6: * applications can interact with Jonah through this API.
7: *
8: * Copyright 2002-2012 Horde LLC (http://www.horde.org/)
9: *
10: * See the enclosed file LICENSE for license information (BSD). If you did not
11: * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
12: *
13: * @author Michael J. Rubinsky <mrubinsk@horde.org>
14: * @package Jonah
15: */
16: class Jonah_Api extends Horde_Registry_Api
17: {
18: /**
19: * Get a list of stored channels.
20: *
21: * @return array An array of channels
22: */
23: public function listFeeds()
24: {
25: return $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannels();
26: }
27:
28: /**
29: * Return the requested stories
30: *
31: * @param integer $channel_id The channel to get the stories from.
32: * @param array $filter Additional, optional filters.
33: * <pre>
34: * max_stories The maximum number of stories to get.
35: * start_at The story number to start retrieving.
36: * order How to order the results.
37: * </pre>
38: *
39: * @return array An array of story information
40: */
41: public function stories($channel_id, $filter = array())
42: {
43: $filter = new Horde_Support_Array($filter);
44:
45: $stories = $GLOBALS['injector']
46: ->getInstance('Jonah_Driver')
47: ->getStories(
48: array(
49: 'channel_id' => $channel_id,
50: 'limit' => $filter->get('max_stories', 10),
51: 'startnumber' => $filter->get('start_at', 0),
52: 'published' => true,
53: )
54: );
55:
56: foreach (array_keys($stories) as $s) {
57: if (empty($stories[$s]['body_type']) || $stories[$s]['body_type'] == 'text') {
58: $stories[$s]['body_html'] = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($stories[$s]['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
59: } else {
60: $stories[$s]['body_html'] = $stories[$s]['body'];
61: }
62: }
63:
64: return $stories;
65: }
66:
67: /**
68: * Fetches a story from a requested channel.
69: *
70: * @param integer $channel_id The channel id to fetch.
71: * @param integer $story_id The story id to fetch.
72: * @param boolean $read Whether to update the read count.
73: *
74: * @return array An array of story data
75: */
76: public function story($channel_id, $story_id, $read = true)
77: {
78: $story = $GLOBALS['injector']->getInstance('Jonah_Driver')->getStory($channel_id, $story_id, $read);
79: if (empty($story['body_type']) || $story['body_type'] == 'text') {
80: $story['body_html'] = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($story['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
81: } else {
82: $story['body_html'] = $story['body'];
83: }
84:
85: return $story;
86: }
87:
88: /**
89: * Publish a new story
90: *
91: * @param integer $channel_id The channel id
92: * @param array $story The story array. Can contain:
93: * <pre>
94: * (string)title [REQUIRED] The story title.
95: * (string)description [REQUIRED] The short description.
96: * (string)body_type [OPTIONAL] The body type (text/html).
97: * (string)body [OPTIONAL] The story body.
98: * (string)url [OPTIONAL] The url for the story link.
99: * (array)tags [OPTIONAL] Tags
100: *</pre>
101: *
102: *
103: * @throws Horde_Exception_PermissionDenied
104: */
105: public function publish($channel_id, $story)
106: {
107: $driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
108: $channel = $driver->getChannel($channel_id);
109: /* Check permissions. */
110: if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::EDIT, $channel_id)) {
111: throw new Horde_Exception_PermissionDenied(_("You are not authorised for this action."));
112: }
113: $story['author'] = $GLOBALS['registry']->getAuth();
114: $story['channel_id'] = $channel_id;
115: $story['published'] = time();
116: if (empty($body) || empty($body_type)) {
117: $story['body_type'] = 'text';
118: }
119: $driver->saveStory($story);
120: }
121:
122: /**
123: * Callback for comment API
124: *
125: * @param integer $id Internal data identifier
126: *
127: * @return mixed Name of object on success | false on failure
128: */
129: public function commentCallback($story_id)
130: {
131: if (!$GLOBALS['conf']['comments']['allow']) {
132: return false;
133: }
134: $story = $GLOBALS['injector']->getInstance('Jonah_Driver')->getStory(null, $story_id);
135:
136: return $story['title'];
137: }
138:
139: /**
140: * Check if comments are allowed.
141: *
142: * @return boolean
143: */
144: public function hasComments()
145: {
146: return $GLOBALS['conf']['comments']['allow'];
147: }
148:
149: /**
150: * Retrieve the list of used tag_names, tag_ids and the total number
151: * of resources that are linked to that tag.
152: *
153: * @param array $tags An optional array of tag_ids. If omitted, all tags
154: * will be included.
155: *
156: * @param array $channel_id An optional array of channel_ids.
157: *
158: * @return array An array containing tag_name, and total
159: */
160: public function listTagInfo($tags = array(), $channel_id = null)
161: {
162: return $GLOBALS['injector']->getInstance('Jonah_Driver')->listTagInfo($tags, $channel_id);
163: }
164:
165: /**
166: * Return a set of tag_ids, given the tag name
167: *
168: * @param array $names An array of names to search for
169: *
170: * @return Array An array of tag_name => tag_ids
171: */
172: public function getTagIds($names)
173: {
174: return $GLOBALS['injector']->getInstance('Jonah_Driver')->getTagIds($names);
175: }
176:
177: /**
178: * Searches internal channels for stories tagged with all requested tags.
179: * Returns an application-agnostic array (useful for when doing a tag search
180: * across multiple applications).
181: *
182: *
183: * The 'raw' story array can be returned instead by setting $raw = true.
184: *
185: * @param array $names An array of tag_names to search for
186: * (AND'd together).
187: * @param array $filter An array of optional filter parameters.
188: * <pre>
189: * max The maximum number of stories to return.
190: * from The number of the story to start with.
191: * channel_id An array of channel_ids to limit the search to.
192: * order How to order the results (a Jonah::ORDER_* constant)
193: * </pre>
194: * @param boolean $raw Return the raw story data?
195: *
196: * @return An array of results with the following structure:
197: * <pre>
198: * 'title' - The title for this resource.
199: * 'desc' - A terse description of this resource.
200: * 'view_url' - The URL to view this resource.
201: * 'app' - The Horde application this resource belongs to.
202: * </pre>
203: *
204: * @TODO Refactor to match the other application's searchTags API signature.
205: */
206: public function searchTags($names, $filter = array(), $raw = false)
207: {
208: global $registry;
209:
210: // @TODO: Refactor when moving tag to content_tagger
211: $filter = new Horde_Support_Array($filter);
212: $results = $GLOBALS['injector']
213: ->getInstance('Jonah_Driver')
214: ->searchTags($names, $filter->max, $filter->from, $filter->channel_id, $filter->order);
215:
216: $return = array();
217: if ($raw) {
218: // Requesting the raw story information as returned from searchTags,
219: // but add some additional information that external apps might
220: // find useful.
221: $comments = $GLOBALS['conf']['comments']['allow'] && $registry->hasMethod('forums/numMessages');
222: foreach ($results as $story) {
223: if (empty($story['body_type']) || $story['body_type'] == 'text') {
224: $story['body_html'] = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($story['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
225: } else {
226: $story['body_html'] = $story['body'];
227: }
228:
229: if ($comments) {
230: $story['num_comments'] = $registry->call('forums/numMessages',
231: array($story['id'],
232: $registry->getApp()));
233: }
234:
235: $return[$story['id']] = $story;
236: }
237: } else {
238: foreach($results as $story) {
239: if (!empty($story)) {
240: $return[] = array('title' => $story['title'],
241: 'desc' => $story['desc'],
242: 'view_url' => $story['link'],
243: 'app' => 'jonah');
244: }
245: }
246: }
247:
248: return $return;
249: }
250:
251: /**
252: * Get the count of stories in the specified channel
253: *
254: * @param int $channel_id
255: * @return mixed The story count
256: */
257: public function storyCount($channel_id)
258: {
259: return $GLOBALS['injector']->getInstance('Jonah_Driver')->getStoryCount($channel_id);
260: }
261:
262: }
263: