Movatterモバイル変換


[0]ホーム

URL:


Jump to content
MediaWiki
Search

API:Holidays viewer

From mediawiki.org
Translate this page
Languages:
This page is part of theMediaWiki Action API documentation.
MediaWiki Action API
Basics
Authentication
Accounts and Users
Page Operations
Search
Developer Utilities
Tutorials
v · d · e

Overview

[edit]

This tutorial covers how to create a demo app that fetches holidays and observances for a given date from Wikipedia, with an option to log in to add new holidays.

Download the code from GitHubBrowse the app on Toolforge

The tools and technologies used to create the demo app are:

A step-by-step process for building this application

[edit]

Step 1: Set up Python and Flask development environment

[edit]

Python comes pre-installed on most Linux distributions.For other operating systems, see thePython beginner's guide for installation instructions.

Install Flask by runningpip install flask.If you don't have Pip, get it fromthe official Pip website


Step 2: Create a simple Flask application

[edit]

In your home directory, create a folder namedholidays-viewer which will contain all the app's files.Inside the folder, create a file namedapp.py and place the following code in it:

#!/usr/bin/python3fromflaskimportFlaskAPP=Flask(__name__)@APP.route("/")deflist_holidays():return"Holidays and observances"if__name__=="__main__":APP.run()

Run the app using the commandpython app.py and openhttp://127.0.0.1:5000/ on your browser.You should see "Holidays and observances" displayed.

Step 3: Create the base layout

[edit]

The app will have four pages: the homepage, a search page, a login page and an add page.Each page will have some common elements, so we need to create a base layout file calledlayout.html to contain these elements.

Note that we are usingBootstrap classes to apply a specific CSS style to an element,Materialize icons for the add, search and arrow-back icons, andJinja to extend the base layout to other pages and to pass variables from Python to HTML.

$HOME/holidays-viewer/templates/layout.html
<title>Holidays</title><linkrel="stylesheet"href="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"><linkrel="stylesheet"href="//tools-static.wmflabs.org/fontcdn/css?family=Material+Icons"><divclass="content bg-secondary rounded m-auto"><divclass="title-bar bg-primary-dark text-white pl-2"><small>Holidays and observances</small></div><divclass="header-bar bg-primary text-white shadow p-2">    {% if request.path != url_for('list_holidays') %}<aclass=" btn text-white"href="{{ url_for('list_holidays') }}"><iclass="material-icons">arrow_back</i></a>    {% endif %}<h5>{{header}}</h5><divclass="filler"></div><aclass="btn text-white"href="{{ url_for('add') }}"><iclass="material-icons">add</i></a><aclass="btn text-white"href="{{ url_for('search') }}"><iclass="material-icons">search</i></a></div>  {% with messages = get_flashed_messages() %}    {% if messages %}<divclass="alert alert-primary mb-0"role="alert">      {% for message in messages %}        {{ message }}      {% endfor %}<buttontype="button"class="close"data-dismiss="alert"aria-label="Close"><spanaria-hidden="true">×</span></button></div>    {% endif %}  {% endwith %}  {% block content %}{% endblock %}</div><scriptsrc="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.min.js"></script>

Other pages will extendlayout.html using the code below:

{% extends "layout.html" %}{% block content %}<!--content for other pages-->{% endblock %}

Step 4: List holidays

[edit]

The root url of the app will trigger thelist_holidays(...) function, which lists holidays for a certain date.

In the function and throughout the app,holidays_date refers to the date of the holidays to be listed,header refers to the title of the page, andholidays_html refers to the html which contains the holidays to be listed.We'll also be using therender_template(...) function which renders a specific html file from the templates directory.Other arguments added to the function are variables which are being passed to the html file.

Inapp.py, updatelist_holidays() with the code below:

@APP.route('/',methods=['GET','POST'])@APP.route('/<holidays_date>',methods=['GET','POST'])deflist_holidays(holidays_date=None):holidays_html=""returnrender_template("index.html",header=holidays_date.replace('_',' '),holidays_html=holidays_html)
$HOME/holidays-viewer/templates/index.html
{% extends "layout.html" %}{% block content %}<divclass="holidays-html">    {{holidays_html|safe}}</div>{% endblock %}

Get today's date

[edit]

If no date is specified, we'll list holidays for today's date.To use Python'sdatetime module to get today's date, import the module withfrom datetime import datetime then create the following function:

defget_todays_date():current_month=datetime.now().strftime('%B')current_day=datetime.now().strftime('%d')ifcurrent_day.startswith('0'):current_day=current_day.replace('0','')returncurrent_month+"_"+current_day

Call the function inlist_holidays(...):

ifholidays_dateisNone:holidays_date=get_todays_date()

Get the holidays to be listed

[edit]

Once we have the date, we get the holidays for that date.Wikipedia has a page for each date and the holidays are under a section titled "Holidays and observances".To get the holidays, we need to get its section number and the content in that section number.

Create a function to get the section number usingAPI:Parse:

defget_holidays_section(url,page,date_to_get):params={"format":"json","action":"parse","prop":"sections","page":page}response=S.get(url=url,params=params)data=response.json()sections=data['parse']['sections']section_number="0"forindex,valueinenumerate(sections):ifvalue['anchor']=="Holidays_and_observances":section_number=index+1ifurl==TEST_URL:ifvalue['anchor']==date_to_get:section_number=index+1returnsection_number

Create a function calledget_holidays(...) to get the holidays in that section usingAPI:Parse as well, then call the functions inlist_holidays(...):

section_number=get_holidays_section(URL,holidays_date,None)holidays=get_holidays(URL,holidays_date,section_number)holidays_html=holidays

Update holiday links

[edit]

The HTML of the holidays returned containsinternal links that point to those holidays, e.g "/wiki/New_Years_Day".We need to prepend "//en.wikipedia.org" to these links using jQuery to make them external links in our app, and make them open in a new tab.To do that, add the following code to$HOME/holidays-viewer/static/update-links.js:

$(document).ready(function(){$(".holidays-html a").attr("target","_blank");$(".holidays-html a").attr("href",function(i,href){return"//en.wikipedia.org"+href;});});

Then add jQuery tolayout.html using:

<scriptsrc="//tools-static.wmflabs.org/cdnjs/ajax/libs/jquery/3.4.1/jquery.min.js"></script><scriptsrc="static/update-links.js"></script>


Step 5: Search for holidays of other dates

[edit]

To get holidays for other dates, create a search route to display a form that collects the month and day to search for:

@APP.route("/search")defsearch():returnrender_template("search.html",header="Search date")
$HOME/holidays-viewer/templates/search.html
{% extends "layout.html" %}{% block content %}<divclass="instructions m-3">    Search for holidays by date</div><divclass="base rounded shadow bg-white m-3"><formclass="m-auto"action="/"method="POST"><fieldset><divclass="label-field">Select Month</div><selectclass="bg-secondary mb-5 border-0"name="monthList"><optionvalue="January">January<optionvalue="February">February<optionvalue="March">March<optionvalue="April">April<optionvalue="May">May<optionvalue="June">June<optionvalue="July">July<optionvalue="August">August<optionvalue="September">September<optionvalue="October">October<optionvalue="November">November<optionvalue="December">December</select></fieldset><fieldset><divclass="label-field">Select Day</div><selectclass="bg-secondary mb-5 border-0"name="dayList"><optionvalue="1">1<optionvalue="2">2<optionvalue="3">3<optionvalue="4">4<optionvalue="5">5<optionvalue="6">6<optionvalue="7">7<optionvalue="8">8<optionvalue="9">9<optionvalue="10">10<optionvalue="11">11<optionvalue="12">12<optionvalue="13">13<optionvalue="14">14<optionvalue="15">15<optionvalue="16">16<optionvalue="17">17<optionvalue="18">18<optionvalue="19">19<optionvalue="20">20<optionvalue="21">21<optionvalue="22">22<optionvalue="23">23<optionvalue="24">24<optionvalue="25">25<optionvalue="26">26<optionvalue="27">27<optionvalue="28">28<optionvalue="29">29<optionvalue="30">30<optionvalue="31">31</select></fieldset><buttontype="submit"name="search"class="bg-primary btn btn-submit text-white">Submit</button></form></div>{% endblock %}

Once the search form has been submitted, updateholidays_date to be the date that has been entered.To do that, add the following code tolist_holidays(...):

ifrequest.method=='POST'and'search'inrequest.form:search_month=str(request.form.get('monthList'))search_day=str(request.form.get('dayList'))holidays_date=search_month+"_"+search_day

Step 6: Add a holiday

[edit]

The page to which we'll be adding a new holiday is protected from edits by anonymous users, so we need to log in usingAPI:Login#clientlogin first.

To add a holiday, send a request toAPI:Edit with the date and description of the holiday.The edit adds new holidays to this page on Test Wikipedia:Sandbox/Holidays_and_observances.This is to prevent adding test holidays to English Wikipedia.

After the holiday is added, redirect to the homepage where the holidays added will also be shown, and formatted in bold to differentiate them from the real holidays.To fetch the test holidays alongside the real holidays, updatelist_holidays(...):

test_section_number=get_holidays_section(TEST_URL,TEST_PAGE,holidays_date)test_holidays=get_holidays(TEST_URL,TEST_PAGE,test_section_number)holidays_html=test_holidays+holidaysflash("Holidays added through this app are in bold")
$HOME/holidays-viewer/templates/login.html
{% extends "layout.html" %}{% block content %}<divclass="instructions m-3"><p>You need to login to Wikipedia in order to add a new holiday</div><divclass="base rounded shadow bg-white m-3"><formclass="m-auto"action="/login"method="POST"><divclass="form-group"><divclass="form-field"><divclass="label-field">Username</div><inputclass="bg-secondary mb-5 border-0"name="username"></div><divclass="form-field"><divclass="label-field">Password</div><inputclass="bg-secondary mb-5 border-0"type="password"name="password"></div></div><buttontype="submit"name="login"class="bg-primary btn btn-submit text-white">Login</button></form></div>{% endblock %}
$HOME/holidays-viewer/templates/add.html
{% extends "layout.html" %}{% block content %}<divclass="instructions m-3"><p>Add a new test holiday</div><divclass="base rounded shadow bg-white m-3"><formclass="m-auto"action=""method="POST"><divclass="form-group"><divclass="form-field"><divclass="label-field">Date [MMMM dd]</div><inputclass="bg-secondary border-0 mb-5"name="date"placeholder="e.g April 1"></div><divclass="form-field"><divclass="label-field">Description</div><inputclass="bg-secondary border-0 mb-5"name="description"placeholder="e.g April fools' day"></div></div><buttontype="submit"name="add"class="bg-primary btn btn-submit text-white">Add</button></form></div>{% endblock %}

Step 7: Styling the app

[edit]

To add more style to our app, create a stylesheet namedstyle.css and link to it fromlayout.html by adding<linkrel="stylesheet"href="static/style.css">.

$HOME/holidays-viewer/static/style.css
.content{width:420px;min-height:100vh;}.holidays-html{overflow-y:auto;overflow-x:hidden;max-height:88vh;scrollbar-width:thin;}.base{height:400px;display:flex;}input,select{width:300px;height:40px;}.btn-submit{width:300px;}.btn{cursor:pointer;align-content:center;background-color:transparent;}.bg-primary{background-color:#36c!important;}.bg-primary-dark{background-color:#2a4b8d!important;}.bg-secondary{background-color:#eaecf0!important;}.header-bar{height:48px;display:flex;flex:1;align-items:center;}.filler{flex-grow:1;text-align:center}h2{display:none;}ul{margin:5px;padding:0;}li{list-style-type:none;margin-bottom:4px;background-color:white;padding:8px;border-radius:5px;}ullili{box-shadow:0.5rem1remrgba(0,0,0,.15);}

Application layout

[edit]

At this point, the structure of your app should be:

$HOME/holidays-viewer├── templates/│   └── add.html    └── index.html    └── layout.html    └── login.html    └── search.html├── static/│   └── style.css    └── update-links.js├── app.py

Withapp.py andlayout.html being:

$HOME/holidays-viewer/app.py
#!/usr/bin/python3"""    app.py    MediaWiki API Demos    Holidays viewer: A demo app that fetches the day's holidays from Wikipedia with options to search for holidays of other dates, and login to add new holidays.    MIT license"""fromdatetimeimportdatetimefromflaskimportFlask,render_template,flash,request,url_for,redirectimportrequestsAPP=Flask(__name__)APP.secret_key='your_secret_key'URL="https://en.wikipedia.org/w/api.php"TEST_URL="https://test.wikipedia.org/w/api.php"TEST_PAGE="Sandbox/Holidays_and_observances"S=requests.Session()IS_LOGGED_IN=False@APP.route('/',methods=['GET','POST'])@APP.route('/<holidays_date>',methods=['GET','POST'])deflist_holidays(holidays_date=None):""" Lists holidays for the current date or a custom date    """ifholidays_dateisNone:holidays_date=get_todays_date()# Update date to a custom dateifrequest.method=='POST'and'search'inrequest.form:search_month=str(request.form.get('monthList'))search_day=str(request.form.get('dayList'))holidays_date=search_month+"_"+search_day# Get the section numbers for the holidays on Wikipedia and for those on the test pagesection_number=get_holidays_section(URL,holidays_date,None)test_section_number=get_holidays_section(TEST_URL,TEST_PAGE,holidays_date)holidays=get_holidays(URL,holidays_date,section_number)test_holidays=get_holidays(TEST_URL,TEST_PAGE,test_section_number)holidays_html=test_holidays+holidaysflash('Holidays added through this app are in bold')returnrender_template("index.html",header=holidays_date.replace('_',' '),holidays_html=holidays_html)defget_todays_date():""" Get the current month as text and the current day as a number    """current_month=datetime.now().strftime('%B')current_day=datetime.now().strftime('%d')ifcurrent_day.startswith('0'):current_day=current_day.replace('0','')returncurrent_month+"_"+current_daydefget_holidays_section(url,page,date_to_get):""" Get the section number for holidays on Wikipedia and holidays on the test page    """params={"format":"json","action":"parse","prop":"sections","page":page}response=S.get(url=url,params=params)data=response.json()sections=data['parse']['sections']section_number="0"forindex,valueinenumerate(sections):ifvalue['anchor']=="Holidays_and_observances":section_number=index+1ifurl==TEST_URL:ifvalue['anchor']==date_to_get:section_number=index+1returnsection_numberdefget_holidays(url,page,section_number):""" Get the html which contains holidays    """params={"format":"json","action":"parse","prop":"text","page":page,"section":section_number,"disableeditsection":1}response=S.get(url=url,params=params)data=response.json()text=data['parse']['text']['*']returntext@APP.route("/search")defsearch():""" Search for holidays of custom dates    """returnrender_template("search.html",header="Search date")@APP.route("/login",methods=['GET','POST'])deflogin():""" Login to Wikipedia    """ifrequest.method=='POST'and'login'inrequest.form:params_0={"action":"query","meta":"tokens","type":"login","format":"json"}response=S.get(url=URL,params=params_0)data=response.json()login_token=data['query']['tokens']['logintoken']params_1={"action":"clientlogin","username":str(request.form.get('username')),"password":str(request.form.get('password')),"loginreturnurl":"http://127.0.0.1:5000/login","logintoken":login_token,"format":"json"}response=S.post(url=URL,data=params_1)data=response.json()ifdata['clientlogin']['status']!='PASS':flash('Oops! Something went wrong -- '+data['clientlogin']['messagecode'])else:globalIS_LOGGED_INIS_LOGGED_IN=Trueflash('Login success! Welcome, '+data['clientlogin']['username']+'!')returnredirect(url_for('add'))returnrender_template("login.html",header="Login")@APP.route("/add",methods=['GET','POST'])defadd():""" Add a new holiday to a test page and redirect to that date's holidays to show the added holidays    """ifnotIS_LOGGED_IN:returnredirect(url_for('login'))ifrequest.method=='POST'and'add'inrequest.form:# Wiki markup to format the added holiday's text as a list item and in boldholiday_text="* '''"+str(request.form.get('description'))+"'''"date=str(request.form.get('date'))params_2={"action":"query","meta":"tokens","format":"json"}response=S.get(url=TEST_URL,params=params_2)data=response.json()csrf_token=data['query']['tokens']['csrftoken']params_4={"action":"edit","title":TEST_PAGE,"token":csrf_token,"format":"json","section":"new","sectiontitle":date,"text":holiday_text,}response=S.post(url=TEST_URL,data=params_4)data=response.json()ifdata['edit']['result']!='Success':flash('Oops! Something went wrong -- '+data['clientlogin']['messagecode'])else:flash('New holiday added successfully!')returnredirect(url_for('list_holidays',holidays_date=date.replace(' ','_')))returnrender_template("add.html",header="Add holiday")if__name__=="__main__":APP.run()
$HOME/holidays-viewer/templates/layout.html
<title>Holidays</title><linkrel="stylesheet"href="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"><linkrel="stylesheet"href="//tools-static.wmflabs.org/fontcdn/css?family=Material+Icons"><linkrel="stylesheet"href="static/style.css"><scriptsrc="//tools-static.wmflabs.org/cdnjs/ajax/libs/jquery/3.4.1/jquery.min.js"></script><scriptsrc="static/update-links.js"></script><divclass="content bg-secondary rounded m-auto"><divclass="title-bar bg-primary-dark text-white pl-2"><small>Holidays and observances</small></div><divclass="header-bar bg-primary text-white shadow p-2">    {% if request.path != url_for('list_holidays') %}<aclass=" btn text-white"href="{{ url_for('list_holidays') }}"><iclass="material-icons">arrow_back</i></a>    {% endif %}<h5>{{header}}</h5><divclass="filler"></div><aclass="btn text-white"href="{{ url_for('add') }}"><iclass="material-icons">add</i></a><aclass="btn text-white"href="{{ url_for('search') }}"><iclass="material-icons">search</i></a></div>  {% with messages = get_flashed_messages() %}    {% if messages %}<divclass="alert alert-primary mb-0"role="alert">      {% for message in messages %}        {{ message }}      {% endfor %}<buttontype="button"class="close"data-dismiss="alert"aria-label="Close"><spanaria-hidden="true">×</span></button></div>    {% endif %}  {% endwith %}  {% block content %}{% endblock %}</div><scriptsrc="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.min.js"></script>
Holidays viewer homepage screenshot

Next steps

[edit]

See also

[edit]
Retrieved from "https://www.mediawiki.org/w/index.php?title=API:Holidays_viewer&oldid=6749968"
Category:

[8]ページ先頭

©2009-2025 Movatter.jp