فهرست منبع

HUE-9096 [gist] Optional public gist link unfurling

Only for Slack currently.
Romain 6 سال پیش
والد
کامیت
6f8ed0d362

+ 4 - 0
desktop/conf.dist/hue.ini

@@ -296,6 +296,10 @@
   # Turn on the Gist snippet sharing.
   ## enable_gist=false
 
+  # Add public description so that the link can be unfurled in a preview by websites like Slack.
+  # Only enabled automatically in private setups.
+  ## enable_gist_preview=true
+
   # Turn on the direct link sharing of saved document.
   ## enable_link_sharing=false
 

+ 4 - 0
desktop/conf/pseudo-distributed.ini.tmpl

@@ -300,6 +300,10 @@
   # Turn on the Gist snippet sharing.
   ## enable_gist=false
 
+  # Add public description so that the link can be unfurled in a preview by websites like Slack.
+  # Only enabled automatically in private setups.
+  ## enable_gist_preview=true
+
   # Turn on the direct link sharing of saved document.
   ## enable_link_sharing=false
 

+ 22 - 9
desktop/core/src/desktop/api2.py

@@ -42,8 +42,8 @@ from metadata.catalog_api import search_entities as metadata_search_entities, _h
 from notebook.connectors.altus import SdxApi, AnalyticDbApi, DataEngApi, DataWarehouse2Api
 from notebook.connectors.base import Notebook, get_interpreter
 
-from desktop.lib.django_util import JsonResponse
-from desktop.conf import get_clusters, IS_K8S_ONLY
+from desktop.lib.django_util import JsonResponse, login_notrequired, render
+from desktop.conf import get_clusters, IS_K8S_ONLY, ENABLE_GIST_PREVIEW
 from desktop.lib.exceptions_renderable import PopupException
 from desktop.lib.export_csvxls import make_response
 from desktop.lib.i18n import smart_str, force_unicode
@@ -855,12 +855,13 @@ def gist_create(request):
   response = {'status': 0}
 
   statement = request.POST.get('statement', '')
-  gist_type = request.POST.get('doc_type', 'query-hive')
+  gist_type = request.POST.get('doc_type', 'hive')
   name = request.POST.get('name', '')
   description = request.POST.get('description', '')
 
   if not name:
-    name = _('%s Query') % gist_type.rsplit('-')[-1].capitalize()
+    name = _('%s Query') % gist_type.capitalize()
+  statement_raw = statement
   if not statement.strip().startswith('--'):
     statement = '-- Created by %s\n\n%s' % (request.user.get_full_name() or request.user.username, statement)
 
@@ -868,7 +869,7 @@ def gist_create(request):
     name=name,
     type='gist',
     owner=request.user,
-    data=json.dumps({'statement': statement}),
+    data=json.dumps({'statement': statement, 'statement_raw': statement_raw}),
     extra=gist_type,
     parent_directory=Document2.objects.get_gist_directory(request.user)
   )
@@ -884,15 +885,27 @@ def gist_create(request):
   return JsonResponse(response)
 
 
+@login_notrequired
 def gist_get(request):
   gist_uuid = request.GET.get('uuid')
 
   gist_doc = _get_gist_document(uuid=gist_uuid)
 
-  return redirect('/hue/editor?gist=%(uuid)s&type=%(type)s' % {
-    'uuid': gist_doc.uuid,
-    'type': gist_doc.extra.rsplit('-')[-1]
-  })
+  if ENABLE_GIST_PREVIEW.get() and 'Slackbot-LinkExpanding' in request.META.get('HTTP_USER_AGENT', ''):
+    statement = json.loads(gist_doc.data)['statement_raw']
+    return render(
+      'unfurl_link.mako',
+      request, {
+        'title': _('SQL gist from %s') % (gist_doc.owner.get_full_name() or gist_doc.owner.username),
+        'description': statement if len(statement) < 30 else (statement[:70] + '...'),
+        'image_link': None
+      }
+    )
+  else:
+    return redirect('/hue/editor?gist=%(uuid)s&type=%(type)s' % {
+      'uuid': gist_doc.uuid,
+      'type': gist_doc.extra
+    })
 
 
 def search_entities(request):

+ 11 - 0
desktop/core/src/desktop/conf.py

@@ -1870,6 +1870,17 @@ ENABLE_GIST = Config(
   help=_('Turn on the Gist snippet sharing.')
 )
 
+def default_gist_preview():
+  """Gist preview only enabled automatically in private setups."""
+  return not ENABLE_ORGANIZATIONS.get()
+
+ENABLE_GIST_PREVIEW = Config(
+  key='enable_gist_preview',
+  dynamic_default=default_gist_preview,
+  type=coerce_bool,
+  help=_('Add public description so that the link can be unfurled in a preview by websites like Slack.')
+)
+
 ENABLE_LINK_SHARING = Config(
   key='enable_link_sharing',
   default=False,

+ 4 - 4
desktop/core/src/desktop/templates/hue.mako

@@ -44,12 +44,12 @@
   <title>Hue</title>
   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
   % if conf.CUSTOM.LOGO_SVG.get():
-  <link rel="icon" type="image/x-icon" href="${ static('desktop/art/custom-branding/favicon.ico') }"/>
+    <link rel="icon" type="image/x-icon" href="${ static('desktop/art/custom-branding/favicon.ico') }"/>
   % else:
-  <link rel="icon" type="image/x-icon" href="${ static('desktop/art/favicon.ico') }"/>
+    <link rel="icon" type="image/x-icon" href="${ static('desktop/art/favicon.ico') }"/>
   % endif
-  <meta name="description" content="">
-  <meta name="author" content="">
+  <meta name="description" content="Open source SQL Query Assistant for Databases/Warehouses.">
+  <meta name="author" content="Hue Team">
 
   <link href="${ static('desktop/css/roboto.css') }" rel="stylesheet">
   <link href="${ static('desktop/ext/css/font-awesome.min.css') }" rel="stylesheet">

+ 50 - 0
desktop/core/src/desktop/templates/unfurl_link.mako

@@ -0,0 +1,50 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##     http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+
+<%!
+  from django.utils.translation import ugettext as _
+
+  from desktop import conf
+%>
+
+<!DOCTYPE html>
+<html lang="en" dir="ltr">
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta charset="utf-8">
+  <title>Hue</title>
+  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+  % if conf.CUSTOM.LOGO_SVG.get():
+    <link rel="icon" type="image/x-icon" href="${ static('desktop/art/custom-branding/favicon.ico') }"/>
+  % else:
+    <link rel="icon" type="image/x-icon" href="${ static('desktop/art/favicon.ico') }"/>
+  % endif
+
+  % if conf.ENABLE_GIST_PREVIEW.get():
+    % if image_link:
+      <meta name="twitter:image" content="${ static(image_link) }">
+    % endif
+    <meta name="twitter:card" content="summary">
+    <meta property="og:site_name" content="Hue" />
+    <meta property="og:title" content="${ title }" />
+    <meta property="og:description" content="${ description }"/>
+  % endif
+</head>
+
+<body>
+</body>
+
+</html>

+ 5 - 0
desktop/core/src/desktop/urls.py

@@ -103,8 +103,12 @@ dynamic_patterns += [
   url(r'^desktop/debug/check_config_ajax$', desktop_views.check_config_ajax),
   url(r'^desktop/log_frontend_event$', desktop_views.log_frontend_event),
 
+  # Catch-up gist
+  url(r'^hue/gist/?$', desktop_api2.gist_get),
+
   # Mobile
   url(r'^assist_m', desktop_views.assist_m),
+
   # Hue 4
   url(r'^hue.*/?$', desktop_views.hue, name='desktop_views_hue'),
   url(r'^403$', desktop_views.path_forbidden),
@@ -171,6 +175,7 @@ dynamic_patterns += [
   url(r'^desktop/api2/gist/create/?$', desktop_api2.gist_create),
   url(r'^desktop/api2/gist/open/?$', desktop_api2.gist_get),
 
+
   url(r'^desktop/api/search/entities/?$', desktop_api2.search_entities),
   url(r'^desktop/api/search/entities_interactive/?$', desktop_api2.search_entities_interactive),
 ]

+ 14 - 12
desktop/libs/notebook/src/notebook/templates/editor.mako

@@ -14,10 +14,12 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 <%!
-  from desktop.views import commonheader, commonfooter, commonshare
+  from django.utils.translation import ugettext as _
+
+  from desktop.views import commonfooter, commonshare
   from desktop import conf
+
   from notebook.conf import ENABLE_NOTEBOOK_2
-  from django.utils.translation import ugettext as _
 %>
 
 <%namespace name="configKoComponents" file="/config_ko_components.mako" />
@@ -27,7 +29,7 @@
 <%namespace name="hueAceAutocompleter" file="/hue_ace_autocompleter.mako" />
 
 <div id="editorComponents" class="editorComponents notebook">
-%if ENABLE_NOTEBOOK_2.get():
+% if ENABLE_NOTEBOOK_2.get():
 <div style="display: flex; flex-direction:column; height: 100%; width: 100%">
   <div style="flex: 0 0 auto;">
   ${ editorComponents2.includes(is_embeddable=is_embeddable, suffix='editor') }
@@ -38,14 +40,14 @@
   </div>
   ${ editorComponents2.commonJS(is_embeddable=is_embeddable, suffix='editor') }
 </div>
-%else:
-${ editorComponents.includes(is_embeddable=is_embeddable, suffix='editor') }
-${ editorComponents.topBar(suffix='editor') }
-${ editorComponents.commonHTML(is_embeddable=is_embeddable, suffix='editor') }
-${ editorComponents.commonJS(is_embeddable=is_embeddable, suffix='editor') }
-%endif
+% else:
+  ${ editorComponents.includes(is_embeddable=is_embeddable, suffix='editor') }
+  ${ editorComponents.topBar(suffix='editor') }
+  ${ editorComponents.commonHTML(is_embeddable=is_embeddable, suffix='editor') }
+  ${ editorComponents.commonJS(is_embeddable=is_embeddable, suffix='editor') }
+% endif
 </div>
 
-%if not is_embeddable:
-${ commonfooter(request, messages) | n,unicode }
-%endif
+% if not is_embeddable:
+  ${ commonfooter(request, messages) | n,unicode }
+% endif

+ 4 - 4
desktop/libs/notebook/src/notebook/templates/notebook.mako

@@ -14,7 +14,7 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 <%!
-  from desktop.views import commonheader, commonfooter, commonshare
+  from desktop.views import commonfooter, commonshare
   from desktop import conf
   from django.utils.translation import ugettext as _
   from notebook.conf import ENABLE_NOTEBOOK_2
@@ -28,7 +28,7 @@
 
 
 <div id="notebookComponents" class="notebook">
-%if ENABLE_NOTEBOOK_2.get():
+% if ENABLE_NOTEBOOK_2.get():
   ${ editorComponents2.includes(is_embeddable=is_embeddable, suffix='notebook') }
   ${ editorComponents2.topBar(suffix='notebook') }
   <%editorComponents2:commonHTML is_embeddable="${is_embeddable}" suffix="notebook">
@@ -53,7 +53,7 @@
   ${ notebookKoComponents.addSnippetMenu() }
 
   ${ editorComponents2.commonJS(is_embeddable=is_embeddable, bindableElement='notebookComponents', suffix='notebook') }
-%else:
+% else:
   ${ editorComponents.includes(is_embeddable=is_embeddable, suffix='notebook') }
   ${ editorComponents.topBar(suffix='notebook') }
   <%editorComponents:commonHTML is_embeddable="${is_embeddable}" suffix="notebook">
@@ -78,5 +78,5 @@
   ${ notebookKoComponents.addSnippetMenu() }
 
   ${ editorComponents.commonJS(is_embeddable=is_embeddable, bindableElement='notebookComponents', suffix='notebook') }
-%endif
+% endif
 </div>