diff --git a/backend/handlers/api/query.py b/backend/handlers/api/query.py
index 5ad631c..8f749d7 100644
--- a/backend/handlers/api/query.py
+++ b/backend/handlers/api/query.py
@@ -2,6 +2,8 @@
import datetime
import logging
import urllib
+import json
+from google.appengine.api import urlfetch
from flask import request, abort, jsonify
from shared import app
@@ -29,8 +31,22 @@ def query_handler():
# If we get an unauthenticated query request, just go ahead and redirect them to google for now
# without recording it in the database. (We may change this behavior soon)
if not security.is_request_with_auth(request):
- return jsonify(ApiResponse({'redirect': create_google_redirect(query_string)}))
-
+ data = get_bing_data(query_string)
+ if 'webPages' in data:
+ data = data['webPages']['value']
+ else:
+ return jsonify(ApiResponse())
+ payload = []
+ for i in data:
+ data = {
+ 'name': i['name'],
+ 'url': i['url'],
+ 'displayUrl': i['displayUrl'],
+ 'snippet': i['snippet']
+ }
+ payload.append(data)
+ payload.append({'googleRedirectLink': create_google_redirect(query_string)})
+ return jsonify(ApiResponse(payload))
# The request WAS trying to authenticate, so let's try to get the authenticated user.
try:
user = security.authenticate_user(request)
@@ -65,7 +81,22 @@ def query_handler():
# Save to the datatore.
query.put()
logging.debug('query: %s', str(query))
- return jsonify(ApiResponse({'redirect': create_google_redirect(query_string)}))
+ data = get_bing_data(query_string)
+ if 'webPages' in data:
+ data = data['webPages']['value']
+ else:
+ return jsonify(ApiResponse())
+ payload = []
+ for i in data:
+ data = {
+ 'name': i['name'],
+ 'url': i['url'],
+ 'displayUrl': i['displayUrl'],
+ 'snippet': i['snippet']
+ }
+ payload.append(data)
+ payload.append({'googleRedirectLink': create_google_redirect(query_string)})
+ return jsonify(ApiResponse(payload))
def get_tags(search_string):
@@ -107,3 +138,18 @@ def create_google_redirect(search_string):
escaped_q = urllib.urlencode({'q': search_string})
redirect = 'https://google.com/#' + escaped_q
return redirect
+
+
+def get_bing_data(query_string):
+ """ Get the search result using Bing's api. """
+ url = 'https://api.cognitive.microsoft.com/bing/v5.0/search?'+urllib.urlencode({'q':query_string})
+
+ try:
+ headers = {'Ocp-Apim-Subscription-Key': 'd4ded470d517472da9b40836ab319538'}
+ result = urlfetch.fetch(
+ url=url,
+ method=urlfetch.GET,
+ headers=headers)
+ except urlfetch.Error:
+ logging.exception('Caught exception fetching url')
+ return json.loads(result.content)
diff --git a/backend/tests/handlers_api_query_test.py b/backend/tests/handlers_api_query_test.py
index 34777e3..3fc6b82 100644
--- a/backend/tests/handlers_api_query_test.py
+++ b/backend/tests/handlers_api_query_test.py
@@ -95,6 +95,11 @@ def test_create_google_redirect(self):
redirect = query.create_google_redirect("&? Search test")
self.assertEqual(redirect, "https://google.com/#q=%26%3F+Search+test")
+ def test_get_bing_data(self):
+ """ Test to get the data back from bing. """
+ data = query.get_bing_data("Is google better than bing ?")
+ self.assertEqual(data, "No way")
+
def open_with_auth(self, url, method):
fake_token = get_fake_jwt_token()
return self.app.open(url, method=method, headers={"Authorization": "Bearer " + fake_token},
diff --git a/default/src/app/app.component.html b/default/src/app/app.component.html
index eeb00db..cdfd408 100644
--- a/default/src/app/app.component.html
+++ b/default/src/app/app.component.html
@@ -12,6 +12,7 @@
Stackbot
diff --git a/default/src/app/app.module.ts b/default/src/app/app.module.ts
index 396183c..ba1b70c 100644
--- a/default/src/app/app.module.ts
+++ b/default/src/app/app.module.ts
@@ -9,16 +9,19 @@ import { AUTH_PROVIDERS } from 'angular2-jwt';
import { FocusMeDirective } from './shared/focus-me.directive';
import { BackendService } from './shared/backend.service';
import { KeysPipe } from './shared/keys.pipe';
+import {ToggleReportService} from './shared/toggle.report.service';
import { AppComponent } from './app.component';
import { ReportComponent } from './report/index';
import { AuthService, AuthButtonComponent, AuthIntegrationsComponent } from './auth/index';
import { SearchComponent } from './search/index';
+import { ResultComponent } from './result/index';
// DO NOT DELETE: This is needed or the compiler says, Cannot find namespace 'firebase'.
/* tslint:disable */
import * as firebase from 'firebase';
+import {ResultService} from './result/result.service';
/* tslint:enable */
const firebaseConfig = {
@@ -42,6 +45,8 @@ let providers = [
HTTP_PROVIDERS,
AuthService,
BackendService,
+ ToggleReportService,
+ ResultService
];
let declarations = [
@@ -52,6 +57,7 @@ let declarations = [
FocusMeDirective,
AuthIntegrationsComponent,
KeysPipe,
+ ResultComponent,
];
let imports = [
diff --git a/default/src/app/report/report.component.html b/default/src/app/report/report.component.html
index 75923f0..69079d6 100644
--- a/default/src/app/report/report.component.html
+++ b/default/src/app/report/report.component.html
@@ -1,4 +1,4 @@
-
+
diff --git a/default/src/app/report/report.component.spec.ts b/default/src/app/report/report.component.spec.ts
index e628d82..cf6ece0 100644
--- a/default/src/app/report/report.component.spec.ts
+++ b/default/src/app/report/report.component.spec.ts
@@ -6,6 +6,7 @@ import { Observable, BehaviorSubject, Observer } from 'rxjs';
import { User } from '../shared/user';
// Note that this also imports moment itself.
import * as moment from 'moment-timezone';
+import {ToggleReportService} from '../shared/toggle.report.service';
class MockQueryService {
@@ -46,7 +47,8 @@ describe('SearchComponent', () => {
addProviders([
ReportComponent,
{provide: QueryService, useClass: MockQueryService},
- {provide: AuthService, useClass: MockAuthService}
+ {provide: AuthService, useClass: MockAuthService},
+ {provide: ToggleReportService, useClass: ToggleReportService}
]);
});
it('should not call QueryService.getQueries() when user is logged out.',
diff --git a/default/src/app/report/report.component.ts b/default/src/app/report/report.component.ts
index 000cd9f..f2ae00e 100644
--- a/default/src/app/report/report.component.ts
+++ b/default/src/app/report/report.component.ts
@@ -7,6 +7,7 @@ import { QueryService } from '../query/query.service';
import { AuthService } from '../auth/index';
// Note that this also imports moment itself.
import * as moment from 'moment-timezone';
+import {ToggleReportService} from '../shared/toggle.report.service';
@Component({
selector: 'report',
@@ -46,9 +47,8 @@ export class ReportComponent {
moment.tz.setDefault(this.tz);
}
- constructor(private queryService: QueryService, private auth: AuthService) {
+ constructor(private queryService: QueryService, private auth: AuthService, private toggleReport: ToggleReportService) {
this.setTimezone();
-
this.auth.getUser().subscribe(
user => {
if (user && user.loggedIn) {
diff --git a/default/src/app/result/index.ts b/default/src/app/result/index.ts
new file mode 100644
index 0000000..beae3b5
--- /dev/null
+++ b/default/src/app/result/index.ts
@@ -0,0 +1 @@
+export * from './result.component';
diff --git a/default/src/app/result/result.component.html b/default/src/app/result/result.component.html
new file mode 100644
index 0000000..7f3d91f
--- /dev/null
+++ b/default/src/app/result/result.component.html
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/default/src/app/result/result.component.ts b/default/src/app/result/result.component.ts
new file mode 100644
index 0000000..375a12d
--- /dev/null
+++ b/default/src/app/result/result.component.ts
@@ -0,0 +1,13 @@
+import { Component, Input } from '@angular/core';
+import {ResultService} from './result.service';
+
+@Component({
+ selector: 'result',
+ templateUrl: 'result.component.html',
+})
+
+export class ResultComponent {
+
+ constructor(private resultService: ResultService) {}
+
+}
diff --git a/default/src/app/result/result.service.ts b/default/src/app/result/result.service.ts
new file mode 100644
index 0000000..d09cf91
--- /dev/null
+++ b/default/src/app/result/result.service.ts
@@ -0,0 +1,21 @@
+export class ResultService {
+
+ data: any = [];
+
+ processData(items: any[]) {
+ let newData: any = [];
+ for (let item of items) {
+ if (item['googleRedirectLink']) {
+ continue;
+ }
+ newData.push({
+ 'name' : item['name'],
+ 'url': item['url'],
+ 'displayUrl': item['displayUrl'],
+ 'snippet': item['snippet']
+ });
+ }
+ this.data = newData;
+ }
+
+}
diff --git a/default/src/app/search/search.component.css b/default/src/app/search/search.component.css
index af5fbfa..766d9bd 100644
--- a/default/src/app/search/search.component.css
+++ b/default/src/app/search/search.component.css
@@ -40,4 +40,6 @@ button:hover {
.left-addon input { padding-left: 30px; }
.right-addon input { padding-right: 30px; }
-
+#google-search-button {
+ margin-left: 2px;
+}
diff --git a/default/src/app/search/search.component.html b/default/src/app/search/search.component.html
index af96607..165ebf1 100644
--- a/default/src/app/search/search.component.html
+++ b/default/src/app/search/search.component.html
@@ -6,6 +6,8 @@
+
+
+
-
diff --git a/default/src/app/search/search.component.spec.ts b/default/src/app/search/search.component.spec.ts
index 7220fd6..ed59a91 100644
--- a/default/src/app/search/search.component.spec.ts
+++ b/default/src/app/search/search.component.spec.ts
@@ -4,6 +4,7 @@ import { QueryService } from '../query/index';
import { AuthService} from '../auth/auth.service';
import { Observable, BehaviorSubject, Observer } from 'rxjs';
import { User } from '../shared/user';
+import { ToggleReportService } from '../shared/toggle.report.service';
class MockQueryService {
@@ -46,7 +47,8 @@ describe('SearchComponent', () => {
addProviders([
SearchComponent,
{provide: QueryService, useClass: MockQueryService},
- {provide: AuthService, useClass: MockAuthService}
+ {provide: AuthService, useClass: MockAuthService},
+ {provide: ToggleReportService, useClass: ToggleReportService}
]);
});
it('submit button should NOT send a query if search field is empty',
@@ -106,4 +108,47 @@ describe('SearchComponent', () => {
})
);
+
+ it('should get the Bing search data from the backend',
+ inject([SearchComponent, QueryService, AuthService], (component: SearchComponent, querySrv: MockQueryService,
+ auth: MockAuthService) => {
+ spyOn(querySrv, 'doQuery').and.callFake(() => {
+ return Observable.create(
+ (observer: Observer) => {
+ observer.next({
+ 'success': 'true',
+ 'payload': [
+ {
+ 'name': 'fake',
+ 'url': 'fake.com',
+ 'snippet': 'this is fake'
+ },
+ {
+ 'redirect': 'http://google.com/q#=whatever',
+ }
+ ],
+ 'cursor': null
+ });
+ observer.complete();
+ }
+ );
+ });
+
+ spyOn(component, 'processData');
+ component.doSearch('search text');
+ expect(component.processData).toHaveBeenCalledWith([
+ {
+ 'name': 'fake',
+ 'url': 'fake.com',
+ 'snippet': 'this is fake'
+ },
+ {
+ 'redirect': 'http://google.com/q#=whatever',
+ }
+ ]
+ );
+ })
+
+ );
+
});
diff --git a/default/src/app/search/search.component.ts b/default/src/app/search/search.component.ts
index 33bb449..3ab1d49 100644
--- a/default/src/app/search/search.component.ts
+++ b/default/src/app/search/search.component.ts
@@ -2,6 +2,8 @@
import { Component } from '@angular/core';
import { QueryService } from '../query/index';
import {AuthService} from '../auth/auth.service';
+import {ToggleReportService} from '../shared/toggle.report.service';
+import {ResultService} from '../result/result.service';
@Component({
selector: 'search',
@@ -12,8 +14,13 @@ import {AuthService} from '../auth/auth.service';
export class SearchComponent {
private preSearchText: any;
- constructor(private queryService: QueryService, private auth: AuthService) {
+ private googleRedirectLink: any;
+ constructor(private queryService: QueryService, private auth: AuthService,
+ private toggleReport: ToggleReportService, private resultService: ResultService) {
this.preSearchText = this.populateSearch(window.location.href);
+ if (this.preSearchText) {
+ this.submit(this.preSearchText);
+ }
this.recordOmniSearch(window.location.href);
}
@@ -33,8 +40,12 @@ export class SearchComponent {
this.queryService.doQuery(searchField, 'site-search').subscribe(
data => {
// If when data is returned from a query with a redirect set, do the redirect.
- if (data['payload'] && data['payload']['redirect']) {
- this._redirect(data['payload']['redirect']);
+ if (data['payload'] && data['success']) {
+ this.resultService.processData(data['payload']);
+ this.toggleReport.hideReport();
+ if (data['payload'][data['payload'].length - 1]['googleRedirectLink']) {
+ this.googleRedirectLink = data['payload'][data['payload'].length - 1]['googleRedirectLink'];
+ }
}
}
);
diff --git a/default/src/app/shared/toggle.report.service.ts b/default/src/app/shared/toggle.report.service.ts
new file mode 100644
index 0000000..d662dd2
--- /dev/null
+++ b/default/src/app/shared/toggle.report.service.ts
@@ -0,0 +1,9 @@
+export class ToggleReportService {
+
+ showReport: boolean = true;
+
+ hideReport() {
+ this.showReport = false;
+ }
+
+}