From 914102f19ff5a67e54db7e249e878fd26cd58f96 Mon Sep 17 00:00:00 2001 From: Ben Halpern Date: Tue, 19 Jun 2018 13:46:10 -0400 Subject: [PATCH] Add basic github support to /connect --- app/assets/stylesheets/chat.scss | 23 ++++ app/controllers/chat_channels_controller.rb | 5 + app/javascript/chat/actions.js | 11 ++ app/javascript/chat/chat.jsx | 6 + app/javascript/chat/content.jsx | 8 ++ app/javascript/chat/githubRepo.jsx | 128 ++++++++++++++++++++ app/javascript/packs/chat.jsx | 3 +- app/views/chat_channels/index.html.erb | 1 + app/views/videos/new.html.erb | 2 +- db/seeds.rb | 9 +- package.json | 1 + yarn.lock | 4 + 12 files changed, 194 insertions(+), 7 deletions(-) create mode 100644 app/javascript/chat/githubRepo.jsx diff --git a/app/assets/stylesheets/chat.scss b/app/assets/stylesheets/chat.scss index b12abfe52..256c8f954 100644 --- a/app/assets/stylesheets/chat.scss +++ b/app/assets/stylesheets/chat.scss @@ -300,6 +300,29 @@ top:-4px; } +.activecontent__githubrepo{ +} + +.activecontent__githubrepoheader{ + padding-left: 30px; + padding-bottom: 3px; + min-height: 30px; + margin-top:-2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.activecontent__githubrepofiles{ + border-bottom: 1px solid $light-medium-gray; + font-size:0.8em; +} + +.activecontent__githubrepofilerow{ + padding: 4px 2px; + border-top: 1px solid $light-medium-gray; +} + .chatchannels { display: flex; flex-direction: column; diff --git a/app/controllers/chat_channels_controller.rb b/app/controllers/chat_channels_controller.rb index ee36cd46f..4cfaa96af 100644 --- a/app/controllers/chat_channels_controller.rb +++ b/app/controllers/chat_channels_controller.rb @@ -99,6 +99,7 @@ class ChatChannelsController < ApplicationController @active_channel = ChatChannel.find_by_slug(slug) @active_channel.current_user = current_user if @active_channel end + generate_github_token generate_algolia_search_key end @@ -109,4 +110,8 @@ class ChatChannelsController < ApplicationController ENV["ALGOLIASEARCH_SEARCH_ONLY_KEY"], params, ) end + + def generate_github_token + @github_token = Identity.where(user_id: current_user.id, provider: "github").first&.token + end end diff --git a/app/javascript/chat/actions.js b/app/javascript/chat/actions.js index 8d7e4b05c..6d5121085 100644 --- a/app/javascript/chat/actions.js +++ b/app/javascript/chat/actions.js @@ -129,4 +129,15 @@ export function getContent(url, successCb, failureCb) { .then(response => response.json()) .then(successCb) .catch(failureCb); +} + +export function getJSONContents(url, successCb, failureCb) { + fetch(url, { + Accept: 'application/json', + 'Content-Type': 'application/json', + credentials: 'same-origin', + }) + .then(response => response.json()) + .then(successCb) + .catch(failureCb); } \ No newline at end of file diff --git a/app/javascript/chat/chat.jsx b/app/javascript/chat/chat.jsx index bd3668d52..a2e37d3f5 100644 --- a/app/javascript/chat/chat.jsx +++ b/app/javascript/chat/chat.jsx @@ -300,6 +300,11 @@ export default class Chat extends Component { } else { alert("Calls are only currently available in direct channels"); } + } else if (message.startsWith('/github')) { + const args = message.split('/github ')[1].trim() + let newActiveContent = this.state.activeContent + newActiveContent[this.state.activeChannelId] = {type_of: "github", args: args } + this.setState({activeContent: newActiveContent}) } else if (message[0] === '/') { conductModeration( this.state.activeChannelId, @@ -545,6 +550,7 @@ export default class Chat extends Component { onExit={this.triggerActiveContent} activeChannelId={this.state.activeChannelId} pusherKey={this.props.pusherKey} + githubToken={this.props.githubToken} /> ); diff --git a/app/javascript/chat/content.jsx b/app/javascript/chat/content.jsx index ad5d0034a..9cef6f48a 100644 --- a/app/javascript/chat/content.jsx +++ b/app/javascript/chat/content.jsx @@ -1,6 +1,7 @@ import { h, Component } from 'preact'; import PropTypes from 'prop-types'; import CodeEditor from './codeEditor'; +import GithubRepo from './githubRepo'; export default class Content extends Component { static propTypes = { @@ -72,6 +73,13 @@ function display(props) {
) + } else if (props.resource.type_of === "github") { + return } else if (props.resource.type_of === "code_editor") { return { + e.preventDefault(); + getJSONContents(`${e.target.dataset.apiUrl}&access_token=`+this.state.token, + this.loadContent, + this.loadFailure) + this.setState({ + root: false, + path: e.target.dataset.path + }) + } + + loadContent = response => { + let files = []; + let directories = []; + console.log(response) + if (response.message === 'Not Found') { + this.setState({path: 'Repo not found (misspelled or private?)'}) + } else if (Array.isArray(response)) { + response.forEach( item => { + if (item.type === 'file') { + files.push(item) + } else { + directories.push(item) + } + }) + this.setState({files: files, + directories: directories, + response: response}) + } else if (response.path === "README.md") { + this.setState({ + readme: window.atob(response.content) + }) + } else if (response.content) { + this.setState({ + content: window.atob(response.content), + response: response + }) + } + } + + loadFailure = response => { + this.setState({path: response.message}) + } + + render() { + if (!this.state.token || this.state.token.length === 0) { + return
+
Authentication required
+

+ You must authenticate with GitHub to use this feature. +

+
+ } else if (this.state.content) { + return
+
{this.state.path}
+
+                  {this.state.content}
+                
+
+ } else { + const directories = this.state.directories.map( item => { + return
+ 📁 {item.name} +
+ }); + const files = this.state.files.map( item => { + return
+ {item.name} +
+ }); + let readme = '' + if (this.state.readme) { + readme =
+ } + if (this.state.root) { + return
+
{this.state.path}
+
+ {directories} + {files} +
+ {readme} +
+ } else { + return
+
{this.state.path}
+
+ {directories} + {files} +
+
+ } + } + } + +} \ No newline at end of file diff --git a/app/javascript/packs/chat.jsx b/app/javascript/packs/chat.jsx index c35de1b9e..f63831a75 100644 --- a/app/javascript/packs/chat.jsx +++ b/app/javascript/packs/chat.jsx @@ -13,7 +13,7 @@ HTMLDocument.prototype.ready = new Promise(resolve => { document.ready.then( getUserDataAndCsrfToken().then(currentUser => { if (document.getElementById('chat')) { - const { chatChannels, pusherKey, chatOptions, algoliaKey, algoliaId, algoliaIndex, twilioToken } = document.getElementById( + const { chatChannels, pusherKey, chatOptions, algoliaKey, algoliaId, algoliaIndex, githubToken } = document.getElementById( 'chat', ).dataset; window.currentUser = currentUser; @@ -30,6 +30,7 @@ document.ready.then( algoliaId={algoliaId} algoliaKey={algoliaKey} algoliaIndex={algoliaIndex} + githubToken={githubToken} />, renderTarget, renderTarget.firstChild ); diff --git a/app/views/chat_channels/index.html.erb b/app/views/chat_channels/index.html.erb index c99c9feda..b1479dde1 100644 --- a/app/views/chat_channels/index.html.erb +++ b/app/views/chat_channels/index.html.erb @@ -18,6 +18,7 @@ data-algolia-id="<%= ENV["ALGOLIASEARCH_APPLICATION_ID"] %>" data-algolia-key="<%= @secured_algolia_key %>" data-algolia-index="<%= "SecuredChatChannel_#{Rails.env}" %>" + data-github-token="<%= @github_token %>" data-chat-channels="<%= [] %>" data-chat-options="<%= {showChannelsList:true, showTimestamp: true, activeChannelId: @active_channel&.id }.to_json %>" > diff --git a/app/views/videos/new.html.erb b/app/views/videos/new.html.erb index d190328d7..4ee101609 100644 --- a/app/views/videos/new.html.erb +++ b/app/views/videos/new.html.erb @@ -18,7 +18,7 @@ key: "video-upload__#{SecureRandom.hex}", key_starts_with: "video-upload__", acl: "public-read", - max_file_size: 2500.megabytes, + max_file_size: (current_user.has_role?(:super_admin) ? 10000 : 3500).megabytes, id: "s3-uploader", class: "upload-form", data: {:key => :val} do %> diff --git a/db/seeds.rb b/db/seeds.rb index d648fda5e..1b73fa602 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -18,7 +18,7 @@ end p "2/7 Creating users" roles = %i(level_1_member level_2_member level_3_member level_4_member workshop_pass) -80.times do |i| +40.times do |i| begin identity_attributes = { provider: "twitter", uid: "#{i}", @@ -123,7 +123,7 @@ Tag.create!( ) p "4/7 Creating articles" -150.times do +80.times do # begin four_tags_string = "discuss, meta, git, changelog" valid_markdown = "---\ntitle: #{Faker::Book.title} #{rand(5000)}\npublished: true\ncover_image: #{Faker::Avatar.image}\ntags: #{four_tags_string}\n---\n#{Faker::Hipster.paragraph(4)}" @@ -142,11 +142,11 @@ end # Create comments p "5/7 Creating comments" -200.times do +120.times do attributes = { body_markdown: Faker::Hipster.paragraph(1), user_id: User.order("RANDOM()").first.id, - commentable_id: Article.order("RANDOM()").first.id, + commentable_id: Article.where("id > ?", 30).order("RANDOM()").first.id, commentable_type: "Article", } Comment.create!(attributes) @@ -164,7 +164,6 @@ podcast_objects = [ podcast_objects.each do |attributes| podcast = Podcast.create!(attributes) - PodcastFeed.new.get_episodes(podcast, 4) end p "7/7 Creating Broadcasts" diff --git a/package.json b/package.json index 65ada14c2..fc16f67e8 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "@webscopeio/react-textarea-autocomplete": "^2.2.0", "codemirror": "^5.38.0", "intersection-observer": "^0.5.0", + "marked": "^0.4.0", "preact": "^8.2.5", "prop-types": "^15.6.0", "pusher-js": "^4.2.2", diff --git a/yarn.lock b/yarn.lock index c1cccea96..6742f3126 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6134,6 +6134,10 @@ marked@^0.3.9: version "0.3.18" resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.18.tgz#3ef058cd926101849b92a7a7c15db18c7fc76b2f" +marked@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.4.0.tgz#9ad2c2a7a1791f10a852e0112f77b571dce10c66" + math-expression-evaluator@^1.2.14: version "1.2.17" resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"